@cat-factory/app 0.311.2 → 0.312.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 +92 -4
- package/app/app.config.ts +7 -0
- package/app/components/assistant/AssistantModal.vue +2 -5
- package/app/components/auth/AuthGate.vue +2 -1
- package/app/components/binaryCandidates/BinaryCandidatesWindow.vue +14 -15
- package/app/components/binaryOutput/StoredAssetView.vue +1 -3
- package/app/components/board/AddTaskModal.vue +3 -10
- package/app/components/board/AgentFailureCard.vue +4 -5
- package/app/components/board/AgentStopButton.vue +5 -7
- package/app/components/board/BoardCanvas.vue +31 -30
- package/app/components/board/CreateInitiativeModal.vue +2 -4
- package/app/components/board/RecurringPipelineModal.vue +2 -7
- package/app/components/board/nodes/AgentChip.vue +3 -2
- package/app/components/board/nodes/BlockNode.vue +14 -11
- package/app/components/board/nodes/InitiativeCard.vue +6 -3
- package/app/components/board/nodes/TaskCard.vue +45 -212
- package/app/components/bootstrap/AdoptionReviewModal.vue +2 -5
- package/app/components/bootstrap/BootstrapModal.vue +6 -15
- package/app/components/bootstrap/BootstrapRunSteps.vue +3 -1
- package/app/components/brainstorm/BrainstormWindow.vue +32 -26
- package/app/components/bugFishing/BugFishingWindow.vue +15 -13
- package/app/components/clarity/ClarityReviewWindow.vue +31 -26
- package/app/components/common/ClarificationItem.vue +3 -1
- package/app/components/common/EmptyState.vue +41 -19
- package/app/components/common/InterviewGateNotice.vue +3 -1
- package/app/components/common/Spinner.vue +28 -0
- package/app/components/consensus/ConsensusSessionWindow.vue +5 -5
- package/app/components/docs/DocInterviewWindow.vue +6 -6
- package/app/components/documents/ContextDocumentPicker.vue +2 -2
- package/app/components/documents/DocumentImportModal.vue +9 -8
- package/app/components/documents/DocumentSourceConnectModal.vue +10 -10
- package/app/components/documents/DocumentTemplatesModal.vue +13 -7
- package/app/components/documents/RepoContextDocPicker.vue +2 -2
- package/app/components/documents/SpawnPreviewModal.vue +4 -6
- package/app/components/documents/StartFromDesignModal.vue +2 -1
- package/app/components/documents/TaskContextDocs.vue +4 -5
- package/app/components/environments/EnvironmentStatusPanel.vue +11 -8
- package/app/components/environments/steps/EnvPickStep.vue +7 -3
- package/app/components/environments/steps/EnvPreflightStep.vue +6 -5
- package/app/components/focus/BlockFocusView.vue +6 -5
- package/app/components/followUp/FollowUpWindow.vue +7 -9
- package/app/components/forkDecision/ForkDecisionWindow.vue +9 -8
- package/app/components/foundational/FoundationalServiceCatalogList.vue +9 -5
- package/app/components/foundational/FoundationalServiceRegistry.vue +11 -7
- package/app/components/foundational/FoundationalServiceSources.vue +20 -22
- package/app/components/foundational/FoundationalSuppressions.vue +2 -2
- package/app/components/foundational/ServiceCatalogConnection.vue +15 -15
- package/app/components/fragments/FragmentLibraryManager.vue +36 -34
- package/app/components/fragments/FragmentSelector.vue +7 -3
- package/app/components/gates/GateResultView.vue +6 -9
- package/app/components/github/AddServiceFromRepoModal.vue +6 -10
- package/app/components/github/GitHubConnect.vue +10 -17
- package/app/components/github/GitHubPanel.vue +44 -47
- package/app/components/github/RepoTreeBrowser.vue +9 -5
- package/app/components/guidedReview/GuidedReviewModal.vue +16 -6
- package/app/components/guidedReview/GuidedReviewOverview.vue +2 -1
- package/app/components/guidedReview/GuidedReviewPicker.vue +10 -7
- package/app/components/guidedReview/GuidedReviewThread.vue +9 -4
- package/app/components/humanTest/HumanTestWindow.vue +2 -1
- package/app/components/initiative/InitiativePlanningWindow.vue +6 -6
- package/app/components/initiative/InitiativeTrackerWindow.vue +11 -11
- package/app/components/judge/JudgeResultView.vue +2 -7
- package/app/components/kaizen/KaizenPanel.vue +20 -5
- package/app/components/kaizen/KaizenStepStatus.vue +2 -1
- package/app/components/layout/AccountAuditLog.vue +11 -3
- package/app/components/layout/AccountDeploymentSettings.vue +17 -62
- package/app/components/layout/AccountFailureKindRules.vue +6 -5
- package/app/components/layout/AccountModelPolicySettings.vue +2 -6
- package/app/components/layout/AccountPlatformAlertSettings.vue +5 -13
- package/app/components/layout/AccountRiskPolicySettings.vue +13 -14
- package/app/components/layout/AccountRunCredentialSettings.vue +2 -2
- package/app/components/layout/AccountTeamSettings.vue +12 -9
- package/app/components/layout/BoardSwitcher.vue +2 -2
- package/app/components/layout/BoardToolbar.vue +27 -37
- package/app/components/layout/BoardTopOverlays.vue +8 -2
- package/app/components/layout/CommandBar.vue +7 -3
- package/app/components/layout/ConnectionStatusBanner.vue +2 -1
- package/app/components/layout/IntegrationsHub.vue +7 -3
- package/app/components/layout/ModelProvidersHub.vue +7 -3
- package/app/components/layout/NotificationsInbox.vue +3 -11
- package/app/components/layout/SideBar.vue +5 -0
- package/app/components/layout/WorkViewSwitcher.vue +64 -0
- package/app/components/layout/WorkspaceMembersSettings.vue +12 -5
- package/app/components/media/ArtifactLightbox.vue +4 -3
- package/app/components/notifications/NotificationSettingsPanel.vue +4 -11
- package/app/components/observability/ToolCallList.vue +12 -17
- package/app/components/panels/AgentStepDetail.vue +5 -5
- package/app/components/panels/GenericStructuredResultView.vue +6 -9
- package/app/components/panels/InspectorPanel.vue +2 -1
- package/app/components/panels/MergerResultView.vue +5 -6
- package/app/components/panels/ObservabilityPanel.vue +26 -41
- package/app/components/panels/OperatorDashboardPanel.vue +29 -17
- package/app/components/panels/ReportsPanel.vue +17 -11
- package/app/components/panels/ReportsSpendBreakdown.vue +7 -3
- package/app/components/panels/RunDetailLoadState.vue +4 -3
- package/app/components/panels/StepContainerStatus.vue +4 -3
- package/app/components/panels/StepDelegatedStatus.vue +3 -2
- package/app/components/panels/StepMetadataCard.vue +6 -8
- package/app/components/panels/StepRunMeta.vue +2 -5
- package/app/components/panels/inspector/ContainerSummary.vue +7 -1
- package/app/components/panels/inspector/EpicChildren.vue +7 -3
- package/app/components/panels/inspector/FrontendConfig.vue +7 -3
- package/app/components/panels/inspector/InitiativeInspector.vue +5 -2
- package/app/components/panels/inspector/ServiceConnections.vue +7 -3
- package/app/components/panels/inspector/ServiceReleaseHealthConfig.vue +2 -6
- package/app/components/panels/inspector/ServiceTestSecrets.vue +2 -6
- package/app/components/panels/inspector/ServiceTestingContext.vue +2 -6
- package/app/components/panels/inspector/ServiceValidationConfig.vue +38 -39
- package/app/components/panels/inspector/TaskExecution.vue +5 -6
- package/app/components/panels/inspector/TaskRunSettings.vue +7 -3
- package/app/components/panels/inspector/TaskStructure.vue +0 -1
- package/app/components/pipeline/AgentPromptEditor.vue +25 -18
- package/app/components/pipeline/PipelineBuilder.vue +14 -24
- package/app/components/pipeline/PipelineProgress.vue +16 -17
- package/app/components/prReview/PrReviewPhaseBadge.vue +3 -2
- package/app/components/prReview/PrReviewWindow.vue +16 -20
- package/app/components/providers/ApiKeysSection.vue +2 -6
- package/app/components/providers/PersonalCredentialModal.vue +2 -6
- package/app/components/providers/PersonalSubscriptionSection.vue +3 -7
- package/app/components/providers/VendorCredentialsModal.vue +2 -6
- package/app/components/provisioning/ProvisioningLogsDrawer.vue +10 -6
- package/app/components/queue/QueueCard.vue +269 -0
- package/app/components/queue/QueueView.vue +192 -0
- package/app/components/ralph/RalphLoopResultView.vue +2 -7
- package/app/components/requirements/RequirementsReviewWindow.vue +44 -39
- package/app/components/sandbox/SandboxPanel.vue +37 -25
- package/app/components/settings/AccountSettingsPanel.vue +6 -3
- package/app/components/settings/ApiTokensPanel.vue +2 -6
- package/app/components/settings/BudgetSettings.vue +2 -2
- package/app/components/settings/CapabilityCredentialsPanel.vue +2 -6
- package/app/components/settings/CloudflareHandlerSection.vue +3 -7
- package/app/components/settings/ConsensusGroupsSection.vue +7 -3
- package/app/components/settings/CustomManifestTypeEditor.vue +7 -3
- package/app/components/settings/DefaultProvisionTypeSection.vue +2 -2
- package/app/components/settings/InfraHandlersConfigurator.vue +8 -11
- package/app/components/settings/IssueTrackerPanel.vue +9 -9
- package/app/components/settings/LocalContainerPoolSettings.vue +2 -6
- package/app/components/settings/LocalModelEndpointsPanel.vue +5 -7
- package/app/components/settings/McpAuthorizeScreen.vue +8 -3
- package/app/components/settings/McpOAuthCallbackScreen.vue +2 -1
- package/app/components/settings/ModelConfigurationPanel.vue +45 -17
- package/app/components/settings/ObservabilityConnectionPanel.vue +4 -15
- package/app/components/settings/OpenRouterCatalogPanel.vue +8 -24
- package/app/components/settings/PackageRegistriesPanel.vue +2 -6
- package/app/components/settings/ProviderConnectionTab.vue +3 -7
- package/app/components/settings/RiskPolicyPanel.vue +4 -16
- package/app/components/settings/SharedStacksPanel.vue +8 -18
- package/app/components/settings/TaskTypeSuppressionsPanel.vue +10 -6
- package/app/components/settings/UsageSettings.vue +11 -2
- package/app/components/settings/UserSecretsSection.vue +5 -7
- package/app/components/settings/WorkspaceMetadataSettings.vue +9 -9
- package/app/components/settings/WorkspaceSettingsPanel.vue +3 -11
- package/app/components/skills/ReviewSkillQueue.vue +7 -3
- package/app/components/skills/SkillLibraryManager.vue +20 -18
- package/app/components/slack/SlackPanel.vue +5 -8
- package/app/components/spec/ServiceSpecWindow.vue +32 -29
- package/app/components/tasks/BugHuntModal.vue +23 -19
- package/app/components/tasks/ContextIssuePicker.vue +2 -2
- package/app/components/tasks/TaskContextIssues.vue +4 -5
- package/app/components/tasks/TaskImportModal.vue +10 -8
- package/app/components/tasks/TaskSourceConnectModal.vue +11 -11
- package/app/components/testing/TestReportWindow.vue +6 -12
- package/app/components/tutorial/TutorialCatalogue.vue +7 -3
- package/app/components/tutorial/TutorialOverlay.vue +2 -1
- package/app/components/tutorial/TutorialPrompt.vue +7 -3
- package/app/components/vcs/GitLabConnect.vue +2 -6
- package/app/components/visualConfirm/VisualConfirmationWindow.vue +9 -4
- package/app/composables/toastTitleKeys.spec.ts +143 -0
- package/app/composables/useActionToast.spec.ts +71 -0
- package/app/composables/useActionToast.ts +101 -0
- package/app/composables/useBlockDeletion.ts +3 -6
- package/app/composables/useConfirmAction.ts +5 -3
- package/app/composables/useContextLinking.spec.ts +3 -0
- package/app/composables/useContextLinking.ts +11 -16
- package/app/composables/useCopyToClipboard.ts +4 -3
- package/app/composables/useFrameLanes.ts +6 -82
- package/app/composables/useNavContributions.ts +6 -5
- package/app/composables/usePipelineErrorToast.spec.ts +24 -0
- package/app/composables/usePipelineErrorToast.ts +26 -2
- package/app/composables/usePipelineLibraryActions.ts +8 -9
- package/app/composables/useTaskActions.ts +254 -0
- package/app/composables/useTaskLaneClassifier.ts +88 -0
- package/app/modular/nav-contributions.spec.ts +4 -0
- package/app/modular/nav-contributions.ts +31 -0
- package/app/modular/tutorial-tours.ts +10 -0
- package/app/pages/index.vue +42 -8
- package/app/stores/board/context.ts +4 -3
- package/app/stores/board/placement.ts +8 -20
- package/app/stores/board/removal.ts +4 -13
- package/app/stores/board.spec.ts +10 -1
- package/app/stores/board.ts +3 -2
- package/app/stores/workView.ts +51 -0
- package/app/stores/workspaceQueue.ts +148 -0
- package/app/utils/bootstrapSteps.ts +11 -2
- package/app/utils/pipelineRender.ts +21 -8
- package/app/utils/queueSections.spec.ts +111 -0
- package/app/utils/queueSections.ts +117 -0
- package/app/utils/workView.spec.ts +16 -0
- package/app/utils/workView.ts +25 -0
- package/i18n/locales/de.json +73 -32
- package/i18n/locales/en.json +73 -32
- package/i18n/locales/es.json +73 -32
- package/i18n/locales/fr.json +73 -32
- package/i18n/locales/he.json +73 -32
- package/i18n/locales/it.json +73 -32
- package/i18n/locales/ja.json +73 -32
- package/i18n/locales/pl.json +73 -32
- package/i18n/locales/tr.json +73 -32
- package/i18n/locales/uk.json +73 -32
- package/package.json +1 -1
|
@@ -19,8 +19,8 @@ const workspace = useWorkspaceStore()
|
|
|
19
19
|
const store = useOpenRouterStore()
|
|
20
20
|
const apiKeys = useApiKeysStore()
|
|
21
21
|
const models = useModelsStore()
|
|
22
|
-
const
|
|
23
|
-
const { present } = usePipelineErrorToast()
|
|
22
|
+
const actionToast = useActionToast()
|
|
23
|
+
const { present, presentReported } = usePipelineErrorToast()
|
|
24
24
|
|
|
25
25
|
const open = computed({
|
|
26
26
|
get: () => ui.openRouterOpen,
|
|
@@ -155,21 +155,14 @@ async function connectKey() {
|
|
|
155
155
|
if (scope === 'workspace') await apiKeys.removeWorkspaceKey(created.id).catch(() => {})
|
|
156
156
|
else await apiKeys.removeUserKey(created.id).catch(() => {})
|
|
157
157
|
}
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
icon: 'i-lucide-triangle-alert',
|
|
162
|
-
color: 'error',
|
|
163
|
-
})
|
|
158
|
+
// `!reachable` covers an outage or a network fault as well as a refused key, and the probe
|
|
159
|
+
// does not say which, so the description stays the generic "it reported a failure" line.
|
|
160
|
+
presentReported(store.refreshError, 'settings.openRouterCatalog.toast.connectFailed')
|
|
164
161
|
return
|
|
165
162
|
}
|
|
166
163
|
keyValue.value = ''
|
|
167
164
|
keyLabel.value = ''
|
|
168
|
-
toast.
|
|
169
|
-
title: t('settings.openRouterCatalog.toast.connected'),
|
|
170
|
-
icon: 'i-lucide-check',
|
|
171
|
-
color: 'success',
|
|
172
|
-
})
|
|
165
|
+
actionToast.success('settings.openRouterCatalog.toast.connected')
|
|
173
166
|
} catch (e) {
|
|
174
167
|
present(e, 'settings.openRouterCatalog.toast.connectFailed')
|
|
175
168
|
} finally {
|
|
@@ -181,12 +174,7 @@ async function refresh() {
|
|
|
181
174
|
if (!workspace.workspaceId) return
|
|
182
175
|
const result = await store.refresh(workspace.workspaceId)
|
|
183
176
|
if (!result.reachable) {
|
|
184
|
-
toast.
|
|
185
|
-
title: t('settings.openRouterCatalog.toast.unreachable'),
|
|
186
|
-
description: store.refreshError ?? t('settings.openRouterCatalog.toast.connectFirst'),
|
|
187
|
-
icon: 'i-lucide-triangle-alert',
|
|
188
|
-
color: 'error',
|
|
189
|
-
})
|
|
177
|
+
presentReported(store.refreshError, 'settings.openRouterCatalog.toast.unreachable')
|
|
190
178
|
}
|
|
191
179
|
}
|
|
192
180
|
|
|
@@ -202,11 +190,7 @@ async function save() {
|
|
|
202
190
|
await store.save(workspace.workspaceId, models2)
|
|
203
191
|
// Reflect newly-enabled models in the picker immediately.
|
|
204
192
|
await models.refresh(workspace.workspaceId)
|
|
205
|
-
toast.
|
|
206
|
-
title: t('settings.openRouterCatalog.toast.saved'),
|
|
207
|
-
icon: 'i-lucide-check',
|
|
208
|
-
color: 'success',
|
|
209
|
-
})
|
|
193
|
+
actionToast.success('settings.openRouterCatalog.toast.saved')
|
|
210
194
|
} catch (e) {
|
|
211
195
|
present(e, 'settings.openRouterCatalog.toast.saveFailed')
|
|
212
196
|
} finally {
|
|
@@ -12,7 +12,7 @@ import SecretInput from '~/components/common/SecretInput.vue'
|
|
|
12
12
|
|
|
13
13
|
const { t } = useI18n()
|
|
14
14
|
const store = usePackageRegistriesStore()
|
|
15
|
-
const
|
|
15
|
+
const actionToast = useActionToast()
|
|
16
16
|
const { present } = usePipelineErrorToast()
|
|
17
17
|
const { confirmAction, toastDone } = useConfirmAction()
|
|
18
18
|
|
|
@@ -70,11 +70,7 @@ async function addEntry() {
|
|
|
70
70
|
})
|
|
71
71
|
form.scopes = ''
|
|
72
72
|
form.token = ''
|
|
73
|
-
toast.
|
|
74
|
-
title: t('settings.packageRegistries.toast.added'),
|
|
75
|
-
icon: 'i-lucide-check',
|
|
76
|
-
color: 'success',
|
|
77
|
-
})
|
|
73
|
+
actionToast.success('settings.packageRegistries.toast.added')
|
|
78
74
|
} catch (e) {
|
|
79
75
|
present(e, 'settings.packageRegistries.toast.addFailed')
|
|
80
76
|
} finally {
|
|
@@ -36,7 +36,7 @@ const emit = defineEmits<{ connected: [] }>()
|
|
|
36
36
|
|
|
37
37
|
const { t } = useI18n()
|
|
38
38
|
const store = useProviderConnectionsStore()
|
|
39
|
-
const
|
|
39
|
+
const actionToast = useActionToast()
|
|
40
40
|
const { present } = usePipelineErrorToast()
|
|
41
41
|
const { confirmAction } = useConfirmAction()
|
|
42
42
|
|
|
@@ -208,11 +208,7 @@ function buildFlatPayload() {
|
|
|
208
208
|
}
|
|
209
209
|
|
|
210
210
|
function toastSaved() {
|
|
211
|
-
toast.
|
|
212
|
-
title: t('settings.providerConnection.toast.saved', { title: title.value }),
|
|
213
|
-
icon: 'i-lucide-check',
|
|
214
|
-
color: 'success',
|
|
215
|
-
})
|
|
211
|
+
actionToast.success('settings.providerConnection.toast.saved', { params: { title: title.value } })
|
|
216
212
|
}
|
|
217
213
|
|
|
218
214
|
// --- Native flat-form actions (both manifest-overlay and config-overlay flavours) ---
|
|
@@ -330,7 +326,7 @@ async function remove() {
|
|
|
330
326
|
try {
|
|
331
327
|
await store.remove(props.kind)
|
|
332
328
|
resetDraft()
|
|
333
|
-
|
|
329
|
+
actionToast.success('settings.providerConnection.toast.removed')
|
|
334
330
|
} catch (e) {
|
|
335
331
|
present(e, 'settings.providerConnection.toast.removeFailed')
|
|
336
332
|
} finally {
|
|
@@ -18,7 +18,7 @@ import SectionLabel from '~/components/common/SectionLabel.vue'
|
|
|
18
18
|
const { t } = useI18n()
|
|
19
19
|
|
|
20
20
|
const store = useRiskPoliciesStore()
|
|
21
|
-
const
|
|
21
|
+
const actionToast = useActionToast()
|
|
22
22
|
const { present } = usePipelineErrorToast()
|
|
23
23
|
const { confirm } = useConfirm()
|
|
24
24
|
|
|
@@ -69,11 +69,7 @@ async function run(key: string, titleKey: string, action: () => Promise<unknown>
|
|
|
69
69
|
async function save(policy: RiskPolicyLibraryEntry, patch: UpdateRiskPolicyInput) {
|
|
70
70
|
await run(policy.id, 'settings.riskPolicy.toast.saveFailed', async () => {
|
|
71
71
|
await store.update(policy.id, patch)
|
|
72
|
-
toast.
|
|
73
|
-
title: t('settings.riskPolicy.toast.saved'),
|
|
74
|
-
icon: 'i-lucide-check',
|
|
75
|
-
color: 'success',
|
|
76
|
-
})
|
|
72
|
+
actionToast.success('settings.riskPolicy.toast.saved')
|
|
77
73
|
})
|
|
78
74
|
}
|
|
79
75
|
|
|
@@ -112,11 +108,7 @@ async function create(input: Parameters<typeof store.create>[0]) {
|
|
|
112
108
|
creating.value = true
|
|
113
109
|
try {
|
|
114
110
|
await store.create(input)
|
|
115
|
-
toast.
|
|
116
|
-
title: t('settings.riskPolicy.toast.created'),
|
|
117
|
-
icon: 'i-lucide-check',
|
|
118
|
-
color: 'success',
|
|
119
|
-
})
|
|
111
|
+
actionToast.success('settings.riskPolicy.toast.created')
|
|
120
112
|
} catch (e) {
|
|
121
113
|
present(e, 'settings.riskPolicy.toast.createFailed')
|
|
122
114
|
} finally {
|
|
@@ -136,11 +128,7 @@ function clone(policy: RiskPolicyLibraryEntry) {
|
|
|
136
128
|
t('settings.riskPolicy.inherited.copyName', { name: source }),
|
|
137
129
|
)
|
|
138
130
|
await store.clone(policy.id, name)
|
|
139
|
-
toast.
|
|
140
|
-
title: t('settings.riskPolicy.toast.cloned'),
|
|
141
|
-
icon: 'i-lucide-check',
|
|
142
|
-
color: 'success',
|
|
143
|
-
})
|
|
131
|
+
actionToast.success('settings.riskPolicy.toast.cloned')
|
|
144
132
|
})
|
|
145
133
|
}
|
|
146
134
|
|
|
@@ -15,8 +15,8 @@ import type {
|
|
|
15
15
|
|
|
16
16
|
const { t } = useI18n()
|
|
17
17
|
const store = useSharedStacksStore()
|
|
18
|
-
const
|
|
19
|
-
const { present } = usePipelineErrorToast()
|
|
18
|
+
const actionToast = useActionToast()
|
|
19
|
+
const { present, presentReported } = usePipelineErrorToast()
|
|
20
20
|
const { confirmAction, toastDone } = useConfirmAction()
|
|
21
21
|
|
|
22
22
|
const stacks = computed(() => store.stacks)
|
|
@@ -150,11 +150,8 @@ async function autodetect() {
|
|
|
150
150
|
...(form.directory.trim() ? { directory: form.directory.trim() } : {}),
|
|
151
151
|
})
|
|
152
152
|
if (!rec.detected) {
|
|
153
|
-
|
|
154
|
-
title: t('settings.sharedStacks.detect.nothing'),
|
|
153
|
+
actionToast.warning('settings.sharedStacks.detect.nothing', {
|
|
155
154
|
description: rec.notes[0]?.message ?? '',
|
|
156
|
-
icon: 'i-lucide-info',
|
|
157
|
-
color: 'warning',
|
|
158
155
|
})
|
|
159
156
|
return
|
|
160
157
|
}
|
|
@@ -163,11 +160,8 @@ async function autodetect() {
|
|
|
163
160
|
form.composeProfiles = rec.composeProfiles.join(', ')
|
|
164
161
|
form.managedNetworks = rec.managedNetworks.join(', ')
|
|
165
162
|
detectedEnvFiles.value = rec.envFiles
|
|
166
|
-
|
|
167
|
-
title: t('settings.sharedStacks.detect.detected'),
|
|
163
|
+
actionToast.success('settings.sharedStacks.detect.detected', {
|
|
168
164
|
description: t('settings.sharedStacks.detect.detectedBody'),
|
|
169
|
-
icon: 'i-lucide-wand-sparkles',
|
|
170
|
-
color: 'success',
|
|
171
165
|
})
|
|
172
166
|
} catch (e) {
|
|
173
167
|
present(e, 'settings.sharedStacks.detect.failed')
|
|
@@ -207,13 +201,9 @@ async function saveStack() {
|
|
|
207
201
|
await store.create(payload)
|
|
208
202
|
}
|
|
209
203
|
resetForm()
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
),
|
|
214
|
-
icon: 'i-lucide-check',
|
|
215
|
-
color: 'success',
|
|
216
|
-
})
|
|
204
|
+
actionToast.success(
|
|
205
|
+
editing ? 'settings.sharedStacks.toast.updated' : 'settings.sharedStacks.toast.created',
|
|
206
|
+
)
|
|
217
207
|
} catch (e) {
|
|
218
208
|
present(
|
|
219
209
|
e,
|
|
@@ -233,7 +223,7 @@ async function start(stack: SharedStack) {
|
|
|
233
223
|
// surface that as an error toast too — not only a thrown transport/unavailable error.
|
|
234
224
|
const updated = await store.ensureUp(stack.id)
|
|
235
225
|
if (updated.status === 'failed') {
|
|
236
|
-
|
|
226
|
+
presentReported(updated.lastError, 'settings.sharedStacks.toast.startFailed')
|
|
237
227
|
}
|
|
238
228
|
} catch (e) {
|
|
239
229
|
present(e, 'settings.sharedStacks.toast.startFailed')
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
// convention); only the chrome around them is i18n.
|
|
13
13
|
import { onMounted, ref } from 'vue'
|
|
14
14
|
import type { TaskTypeSuppression } from '~/types/domain'
|
|
15
|
+
import EmptyState from '~/components/common/EmptyState.vue'
|
|
15
16
|
|
|
16
17
|
const { t } = useI18n()
|
|
17
18
|
const api = useApi()
|
|
@@ -65,12 +66,15 @@ async function toggle(row: TaskTypeSuppression, offered: boolean) {
|
|
|
65
66
|
{{ t('settings.taskTypeSuppressions.intro') }}
|
|
66
67
|
</p>
|
|
67
68
|
|
|
68
|
-
<
|
|
69
|
-
|
|
70
|
-
</
|
|
71
|
-
<
|
|
72
|
-
|
|
73
|
-
|
|
69
|
+
<div v-if="loading" class="space-y-2">
|
|
70
|
+
<USkeleton v-for="n in 3" :key="n" class="h-12 w-full" />
|
|
71
|
+
</div>
|
|
72
|
+
<EmptyState
|
|
73
|
+
v-else-if="!rows.length"
|
|
74
|
+
compact
|
|
75
|
+
icon="i-lucide-list-checks"
|
|
76
|
+
:title="t('settings.taskTypeSuppressions.empty')"
|
|
77
|
+
/>
|
|
74
78
|
<ul v-else class="space-y-2" data-testid="task-type-suppressions">
|
|
75
79
|
<li
|
|
76
80
|
v-for="row in rows"
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
// only the metered rows. See docs/initiatives/usage-and-quota-tracking.md.
|
|
6
6
|
import { computed, watch } from 'vue'
|
|
7
7
|
import type { UsageBreakdownRow } from '@cat-factory/contracts'
|
|
8
|
+
import EmptyState from '~/components/common/EmptyState.vue'
|
|
8
9
|
|
|
9
10
|
const { t, n, d } = useI18n()
|
|
10
11
|
const usage = useUsageStore()
|
|
@@ -46,9 +47,17 @@ const hasAny = computed(() => usage.rows.length > 0)
|
|
|
46
47
|
{{ t('settings.usage.period', { date: d(new Date(usage.report.periodStart), 'short') }) }}
|
|
47
48
|
</p>
|
|
48
49
|
|
|
49
|
-
<
|
|
50
|
+
<div v-if="usage.loading" class="space-y-3">
|
|
51
|
+
<USkeleton class="h-5 w-1/3" />
|
|
52
|
+
<USkeleton v-for="n in 3" :key="n" class="h-8 w-full" />
|
|
53
|
+
</div>
|
|
50
54
|
<p v-else-if="usage.error" class="text-2xs text-app-error-400">{{ usage.error }}</p>
|
|
51
|
-
<
|
|
55
|
+
<EmptyState
|
|
56
|
+
v-else-if="!hasAny"
|
|
57
|
+
compact
|
|
58
|
+
icon="i-lucide-chart-bar"
|
|
59
|
+
:title="t('settings.usage.empty')"
|
|
60
|
+
/>
|
|
52
61
|
|
|
53
62
|
<template v-else>
|
|
54
63
|
<!-- Subscriptions (flat-rate quota harnesses) -->
|
|
@@ -15,7 +15,7 @@ import SectionLabel from '~/components/common/SectionLabel.vue'
|
|
|
15
15
|
const { t } = useI18n()
|
|
16
16
|
const ui = useUiStore()
|
|
17
17
|
const store = useUserSecretsStore()
|
|
18
|
-
const
|
|
18
|
+
const actionToast = useActionToast()
|
|
19
19
|
const { present } = usePipelineErrorToast()
|
|
20
20
|
const { confirm } = useConfirm()
|
|
21
21
|
|
|
@@ -105,12 +105,10 @@ async function save() {
|
|
|
105
105
|
// (backend/docs/security-model.md). Best-effort: the save already succeeded, so a probe
|
|
106
106
|
// failure must not read as one.
|
|
107
107
|
testResult.value = await store.test(kind.value, payload).catch(() => null)
|
|
108
|
-
toast.
|
|
109
|
-
|
|
108
|
+
actionToast.success('settings.userSecrets.toast.saved', {
|
|
109
|
+
params: {
|
|
110
110
|
label: descriptor.value?.label ?? t('settings.userSecrets.secretFallback'),
|
|
111
|
-
}
|
|
112
|
-
icon: 'i-lucide-check',
|
|
113
|
-
color: 'success',
|
|
111
|
+
},
|
|
114
112
|
})
|
|
115
113
|
} catch (e) {
|
|
116
114
|
present(e, 'settings.userSecrets.toast.saveFailed')
|
|
@@ -134,7 +132,7 @@ async function remove() {
|
|
|
134
132
|
try {
|
|
135
133
|
await store.remove(kind.value)
|
|
136
134
|
resetDraft()
|
|
137
|
-
|
|
135
|
+
actionToast.success('settings.userSecrets.toast.removed')
|
|
138
136
|
} catch (e) {
|
|
139
137
|
present(e, 'settings.userSecrets.toast.removeFailed')
|
|
140
138
|
} finally {
|
|
@@ -18,11 +18,12 @@ import {
|
|
|
18
18
|
import type { WorkspaceMetadataFieldDefinition } from '~/modular/workspace-metadata'
|
|
19
19
|
import type { AppSlots } from '~/modular/slots'
|
|
20
20
|
import SectionLabel from '~/components/common/SectionLabel.vue'
|
|
21
|
+
import EmptyState from '~/components/common/EmptyState.vue'
|
|
21
22
|
|
|
22
23
|
const { t } = useI18n()
|
|
23
24
|
const slots = useReactiveSlots<AppSlots>()
|
|
24
25
|
const store = useWorkspaceSettingsStore()
|
|
25
|
-
const
|
|
26
|
+
const actionToast = useActionToast()
|
|
26
27
|
const { present } = usePipelineErrorToast()
|
|
27
28
|
|
|
28
29
|
/**
|
|
@@ -67,11 +68,7 @@ async function save() {
|
|
|
67
68
|
await store.update({
|
|
68
69
|
metadata: metadataPatchFrom(fields.value, draft, store.settings.metadata),
|
|
69
70
|
})
|
|
70
|
-
toast.
|
|
71
|
-
title: t('settings.workspaceSettings.toast.saved'),
|
|
72
|
-
icon: 'i-lucide-check',
|
|
73
|
-
color: 'success',
|
|
74
|
-
})
|
|
71
|
+
actionToast.success('settings.workspaceSettings.toast.saved')
|
|
75
72
|
} catch (e) {
|
|
76
73
|
present(e, 'settings.workspaceSettings.toast.saveFailed')
|
|
77
74
|
} finally {
|
|
@@ -99,9 +96,12 @@ function selectItems(field: WorkspaceMetadataFieldDefinition) {
|
|
|
99
96
|
</p>
|
|
100
97
|
</section>
|
|
101
98
|
|
|
102
|
-
<
|
|
103
|
-
|
|
104
|
-
|
|
99
|
+
<EmptyState
|
|
100
|
+
v-if="fields.length === 0"
|
|
101
|
+
compact
|
|
102
|
+
icon="i-lucide-tags"
|
|
103
|
+
:title="t('settings.workspaceSettings.metadata.empty')"
|
|
104
|
+
/>
|
|
105
105
|
|
|
106
106
|
<template v-else>
|
|
107
107
|
<div class="space-y-4">
|
|
@@ -32,7 +32,7 @@ const store = useWorkspaceSettingsStore()
|
|
|
32
32
|
const workspace = useWorkspaceStore()
|
|
33
33
|
const access = useWorkspaceAccess()
|
|
34
34
|
const pipelines = usePipelinesStore()
|
|
35
|
-
const
|
|
35
|
+
const actionToast = useActionToast()
|
|
36
36
|
const { present } = usePipelineErrorToast()
|
|
37
37
|
const slots = useReactiveSlots<AppSlots>()
|
|
38
38
|
// Whether the deployment registers any reusable operation at all, hidden or not, so the
|
|
@@ -283,11 +283,7 @@ async function save() {
|
|
|
283
283
|
// Mirror the backend's enforce-mode validation client-side so the user gets an immediate,
|
|
284
284
|
// localized message instead of the raw 422 (enforce needs at least one hard trigger).
|
|
285
285
|
if (draft.reviewFrictionMode === 'enforce' && blockCount == null && blockStuckMinutes == null) {
|
|
286
|
-
|
|
287
|
-
title: t('settings.workspaceSettings.reviewFriction.needsTrigger'),
|
|
288
|
-
icon: 'i-lucide-triangle-alert',
|
|
289
|
-
color: 'warning',
|
|
290
|
-
})
|
|
286
|
+
actionToast.error('settings.workspaceSettings.reviewFriction.needsTrigger')
|
|
291
287
|
return
|
|
292
288
|
}
|
|
293
289
|
saving.value = true
|
|
@@ -322,11 +318,7 @@ async function save() {
|
|
|
322
318
|
reviewFrictionBlockCount: blockCount,
|
|
323
319
|
reviewFrictionBlockStuckMinutes: blockStuckMinutes,
|
|
324
320
|
})
|
|
325
|
-
toast.
|
|
326
|
-
title: t('settings.workspaceSettings.toast.saved'),
|
|
327
|
-
icon: 'i-lucide-check',
|
|
328
|
-
color: 'success',
|
|
329
|
-
})
|
|
321
|
+
actionToast.success('settings.workspaceSettings.toast.saved')
|
|
330
322
|
} catch (e) {
|
|
331
323
|
present(e, 'settings.workspaceSettings.toast.saveFailed')
|
|
332
324
|
} finally {
|
|
@@ -18,6 +18,7 @@ import { computed, ref } from 'vue'
|
|
|
18
18
|
import { MAX_REVIEW_SKILLS } from '@cat-factory/contracts'
|
|
19
19
|
import { useSkillsStore } from '~/stores/skills'
|
|
20
20
|
import SectionLabel from '~/components/common/SectionLabel.vue'
|
|
21
|
+
import EmptyState from '~/components/common/EmptyState.vue'
|
|
21
22
|
|
|
22
23
|
const props = defineProps<{
|
|
23
24
|
/** The queued skill ids, in the order the reviewer applies them (`v-model`). */
|
|
@@ -109,9 +110,12 @@ function toggle(id: string) {
|
|
|
109
110
|
</span>
|
|
110
111
|
</UButton>
|
|
111
112
|
</template>
|
|
112
|
-
<
|
|
113
|
-
|
|
114
|
-
|
|
113
|
+
<EmptyState
|
|
114
|
+
v-else
|
|
115
|
+
compact
|
|
116
|
+
icon="i-lucide-book-open-check"
|
|
117
|
+
:title="t('skills.reviewQueue.pickerEmpty')"
|
|
118
|
+
/>
|
|
115
119
|
</div>
|
|
116
120
|
|
|
117
121
|
<p
|
|
@@ -13,12 +13,13 @@ 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
15
|
import IconButton from '~/components/common/IconButton.vue'
|
|
16
|
+
import EmptyState from '~/components/common/EmptyState.vue'
|
|
16
17
|
|
|
17
18
|
const props = defineProps<{ accountId: string }>()
|
|
18
19
|
|
|
19
20
|
const library = useSkillLibrary(props.accountId)
|
|
20
21
|
const github = useGitHubStore()
|
|
21
|
-
const
|
|
22
|
+
const actionToast = useActionToast()
|
|
22
23
|
const { present } = usePipelineErrorToast()
|
|
23
24
|
const { t, d } = useI18n()
|
|
24
25
|
const { confirm } = useConfirm()
|
|
@@ -85,7 +86,7 @@ async function linkSource() {
|
|
|
85
86
|
gitRef: sourceRef.value.trim() || undefined,
|
|
86
87
|
})
|
|
87
88
|
resetSourceDraft()
|
|
88
|
-
|
|
89
|
+
actionToast.success('skills.toast.sourceLinked')
|
|
89
90
|
} catch (e) {
|
|
90
91
|
present(e, 'skills.toast.linkSourceFailed')
|
|
91
92
|
} finally {
|
|
@@ -97,13 +98,11 @@ async function syncSource(id: string) {
|
|
|
97
98
|
await withRow(`sync:${id}`, async () => {
|
|
98
99
|
try {
|
|
99
100
|
const result = await library.syncSource(id)
|
|
100
|
-
toast.
|
|
101
|
-
|
|
101
|
+
actionToast.success('skills.toast.synced', {
|
|
102
|
+
params: {
|
|
102
103
|
updated: result.upserted,
|
|
103
104
|
removed: result.tombstoned,
|
|
104
|
-
}
|
|
105
|
-
icon: 'i-lucide-refresh-cw',
|
|
106
|
-
color: 'info',
|
|
105
|
+
},
|
|
107
106
|
})
|
|
108
107
|
} catch (e) {
|
|
109
108
|
present(e, 'skills.toast.syncFailed')
|
|
@@ -115,10 +114,7 @@ async function checkSource(id: string) {
|
|
|
115
114
|
await withRow(`check:${id}`, async () => {
|
|
116
115
|
try {
|
|
117
116
|
const status = await library.checkSource(id)
|
|
118
|
-
toast.
|
|
119
|
-
title: status.changed ? t('skills.toast.changesAvailable') : t('skills.toast.upToDate'),
|
|
120
|
-
icon: status.changed ? 'i-lucide-bell-dot' : 'i-lucide-check',
|
|
121
|
-
})
|
|
117
|
+
actionToast.info(status.changed ? 'skills.toast.changesAvailable' : 'skills.toast.upToDate')
|
|
122
118
|
} catch (e) {
|
|
123
119
|
present(e, 'skills.toast.checkSourceFailed')
|
|
124
120
|
}
|
|
@@ -139,7 +135,7 @@ async function unlinkSource(id: string) {
|
|
|
139
135
|
await withRow(`unlink:${id}`, async () => {
|
|
140
136
|
try {
|
|
141
137
|
await library.unlinkSource(id)
|
|
142
|
-
|
|
138
|
+
actionToast.success('skills.toast.sourceUnlinked')
|
|
143
139
|
} catch (e) {
|
|
144
140
|
present(e, 'skills.toast.unlinkSourceFailed')
|
|
145
141
|
}
|
|
@@ -195,9 +191,12 @@ async function unlinkSource(id: string) {
|
|
|
195
191
|
</p>
|
|
196
192
|
</div>
|
|
197
193
|
</div>
|
|
198
|
-
<
|
|
199
|
-
|
|
200
|
-
|
|
194
|
+
<EmptyState
|
|
195
|
+
v-if="!library.catalog.length"
|
|
196
|
+
compact
|
|
197
|
+
icon="i-lucide-book-open-check"
|
|
198
|
+
:title="t('skills.catalog.empty')"
|
|
199
|
+
/>
|
|
201
200
|
</div>
|
|
202
201
|
|
|
203
202
|
<!-- Repo sources -->
|
|
@@ -264,9 +263,12 @@ async function unlinkSource(id: string) {
|
|
|
264
263
|
/>
|
|
265
264
|
</div>
|
|
266
265
|
</div>
|
|
267
|
-
<
|
|
268
|
-
|
|
269
|
-
|
|
266
|
+
<EmptyState
|
|
267
|
+
v-if="!library.sources.length"
|
|
268
|
+
compact
|
|
269
|
+
icon="i-lucide-git-branch"
|
|
270
|
+
:title="t('skills.sources.empty')"
|
|
271
|
+
/>
|
|
270
272
|
|
|
271
273
|
<!-- Link a new source. Needs the GitHub integration; hide the form when it's off. -->
|
|
272
274
|
<div
|
|
@@ -20,7 +20,7 @@ import SectionLabel from '~/components/common/SectionLabel.vue'
|
|
|
20
20
|
|
|
21
21
|
const ui = useUiStore()
|
|
22
22
|
const slack = useSlackStore()
|
|
23
|
-
const
|
|
23
|
+
const actionToast = useActionToast()
|
|
24
24
|
const { present } = usePipelineErrorToast()
|
|
25
25
|
const { t } = useI18n()
|
|
26
26
|
const { confirm } = useConfirm()
|
|
@@ -134,7 +134,7 @@ async function connectWithToken() {
|
|
|
134
134
|
try {
|
|
135
135
|
await slack.connectWithToken(tokenInput.value.trim())
|
|
136
136
|
tokenInput.value = ''
|
|
137
|
-
|
|
137
|
+
actionToast.success('slack.toast.connected')
|
|
138
138
|
} catch (e) {
|
|
139
139
|
present(e, 'slack.error.connect')
|
|
140
140
|
}
|
|
@@ -163,7 +163,7 @@ async function saveRouting() {
|
|
|
163
163
|
routes: { ...routes },
|
|
164
164
|
mentionsEnabled: mentionsEnabled.value,
|
|
165
165
|
})
|
|
166
|
-
|
|
166
|
+
actionToast.success('slack.toast.routingSaved')
|
|
167
167
|
} catch (e) {
|
|
168
168
|
present(e, 'slack.error.saveRouting')
|
|
169
169
|
} finally {
|
|
@@ -182,11 +182,8 @@ async function saveMapping() {
|
|
|
182
182
|
// dropped on save (UX-23) — block instead so the user doesn't lose the entry. A
|
|
183
183
|
// fully-empty row is just an unused slot and is ignored.
|
|
184
184
|
if (hasHalfFilledRow(mapping.value)) {
|
|
185
|
-
|
|
186
|
-
title: t('slack.members.incompleteTitle'),
|
|
185
|
+
actionToast.error('slack.members.incompleteTitle', {
|
|
187
186
|
description: t('slack.members.incompleteBody'),
|
|
188
|
-
icon: 'i-lucide-triangle-alert',
|
|
189
|
-
color: 'warning',
|
|
190
187
|
})
|
|
191
188
|
return
|
|
192
189
|
}
|
|
@@ -195,7 +192,7 @@ async function saveMapping() {
|
|
|
195
192
|
const entries = toMemberEntries(mapping.value)
|
|
196
193
|
await slack.updateMemberMapping(entries)
|
|
197
194
|
mapping.value = slack.memberMapping.map((e) => toMemberRow(e, nextUid()))
|
|
198
|
-
|
|
195
|
+
actionToast.success('slack.toast.mapSaved')
|
|
199
196
|
} catch (e) {
|
|
200
197
|
present(e, 'slack.error.saveMap')
|
|
201
198
|
} finally {
|