@cat-factory/app 0.311.1 → 0.311.3
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 +70 -5
- package/app/app.config.ts +6 -18
- 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/bootstrap/AdoptionReviewModal.vue +4 -7
- 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/AsyncViewError.vue +1 -1
- 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 +15 -9
- 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 +3 -11
- 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 +1 -1
- 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/ResultWindowShell.vue +1 -1
- 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/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/useNavContributions.ts +4 -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/pages/index.vue +3 -2
- 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/utils/bootstrapSteps.ts +11 -2
- package/app/utils/pipelineRender.ts +21 -8
- package/i18n/locales/de.json +12 -30
- package/i18n/locales/en.json +12 -30
- package/i18n/locales/es.json +12 -30
- package/i18n/locales/fr.json +12 -30
- package/i18n/locales/he.json +12 -30
- package/i18n/locales/it.json +12 -30
- package/i18n/locales/ja.json +12 -30
- package/i18n/locales/pl.json +12 -30
- package/i18n/locales/tr.json +12 -30
- package/i18n/locales/uk.json +12 -30
- package/package.json +1 -1
|
@@ -3,6 +3,7 @@ import type { DocumentSourceKind } from '~/types/domain'
|
|
|
3
3
|
import DocumentSyncState from '~/components/documents/DocumentSyncState.vue'
|
|
4
4
|
import IntegrationBackTitle from '~/components/layout/IntegrationBackTitle.vue'
|
|
5
5
|
import SectionLabel from '~/components/common/SectionLabel.vue'
|
|
6
|
+
import EmptyState from '~/components/common/EmptyState.vue'
|
|
6
7
|
|
|
7
8
|
// Import pages from a connected document source and pick one to expand into
|
|
8
9
|
// board structure. A source selector lets the user choose which connected source
|
|
@@ -11,7 +12,7 @@ import SectionLabel from '~/components/common/SectionLabel.vue'
|
|
|
11
12
|
const { t } = useI18n()
|
|
12
13
|
const ui = useUiStore()
|
|
13
14
|
const documents = useDocumentsStore()
|
|
14
|
-
const
|
|
15
|
+
const actionToast = useActionToast()
|
|
15
16
|
const { present } = usePipelineErrorToast()
|
|
16
17
|
|
|
17
18
|
const open = computed({
|
|
@@ -58,10 +59,7 @@ async function doImport() {
|
|
|
58
59
|
try {
|
|
59
60
|
const doc = await documents.importDocument(source.value, value)
|
|
60
61
|
ref_.value = ''
|
|
61
|
-
|
|
62
|
-
title: t('documents.import.imported', { title: doc.title }),
|
|
63
|
-
icon: 'i-lucide-file-down',
|
|
64
|
-
})
|
|
62
|
+
actionToast.success('documents.import.imported', { params: { title: doc.title } })
|
|
65
63
|
} catch (e) {
|
|
66
64
|
present(e, 'documents.import.importFailed')
|
|
67
65
|
} finally {
|
|
@@ -157,9 +155,12 @@ function preview(externalId: string) {
|
|
|
157
155
|
</div>
|
|
158
156
|
</div>
|
|
159
157
|
</div>
|
|
160
|
-
<
|
|
161
|
-
|
|
162
|
-
|
|
158
|
+
<EmptyState
|
|
159
|
+
v-else
|
|
160
|
+
compact
|
|
161
|
+
icon="i-lucide-file-down"
|
|
162
|
+
:title="t('documents.import.noneImported')"
|
|
163
|
+
/>
|
|
163
164
|
</div>
|
|
164
165
|
</template>
|
|
165
166
|
</UModal>
|
|
@@ -17,7 +17,7 @@ import SecretInput from '~/components/common/SecretInput.vue'
|
|
|
17
17
|
const { t } = useI18n()
|
|
18
18
|
const ui = useUiStore()
|
|
19
19
|
const documents = useDocumentsStore()
|
|
20
|
-
const
|
|
20
|
+
const actionToast = useActionToast()
|
|
21
21
|
const { present } = usePipelineErrorToast()
|
|
22
22
|
const { confirmAction } = useConfirmAction()
|
|
23
23
|
|
|
@@ -82,10 +82,8 @@ async function submit() {
|
|
|
82
82
|
saving.value = true
|
|
83
83
|
try {
|
|
84
84
|
await documents.connect(source.value, credentials)
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
icon: 'i-lucide-check',
|
|
88
|
-
color: 'success',
|
|
85
|
+
actionToast.success('documents.connect.connected', {
|
|
86
|
+
params: { source: descriptor.value!.label },
|
|
89
87
|
})
|
|
90
88
|
ui.closeDocumentConnect()
|
|
91
89
|
} catch (e) {
|
|
@@ -99,11 +97,13 @@ async function disconnect() {
|
|
|
99
97
|
if (!source.value) return
|
|
100
98
|
const label = descriptor.value?.label ?? t('documents.connect.sourceFallback')
|
|
101
99
|
if (!(await confirmAction('disconnect', label))) return
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
100
|
+
try {
|
|
101
|
+
await documents.disconnect(source.value)
|
|
102
|
+
} catch (e) {
|
|
103
|
+
present(e, 'documents.connect.disconnectFailed')
|
|
104
|
+
return
|
|
105
|
+
}
|
|
106
|
+
actionToast.success('documents.connect.disconnected', { params: { source: label } })
|
|
107
107
|
ui.closeDocumentConnect()
|
|
108
108
|
}
|
|
109
109
|
</script>
|
|
@@ -4,6 +4,7 @@ import type { DocKind, DocumentLinkRole, SourceDocument } from '~/types/domain'
|
|
|
4
4
|
import DocumentOriginLink from '~/components/documents/DocumentOriginLink.vue'
|
|
5
5
|
import IntegrationBackTitle from '~/components/layout/IntegrationBackTitle.vue'
|
|
6
6
|
import SectionLabel from '~/components/common/SectionLabel.vue'
|
|
7
|
+
import EmptyState from '~/components/common/EmptyState.vue'
|
|
7
8
|
|
|
8
9
|
// Manage the workspace's per-DocKind TEMPLATE (singular) + EXEMPLAR (multi) document links (WS1).
|
|
9
10
|
// A kind can be pointed at one of the workspace's already-imported documents so its parsed
|
|
@@ -97,13 +98,15 @@ async function unlink(doc: SourceDocument) {
|
|
|
97
98
|
<p class="text-xs text-muted">{{ t('documents.templates.intro') }}</p>
|
|
98
99
|
|
|
99
100
|
<!-- No imported documents yet: a template/exemplar must be an imported document. -->
|
|
100
|
-
<
|
|
101
|
-
|
|
102
|
-
|
|
101
|
+
<EmptyState
|
|
102
|
+
v-if="!documents.documents.length"
|
|
103
|
+
icon="i-lucide-file-plus"
|
|
104
|
+
:title="t('documents.templates.importFirst')"
|
|
105
|
+
>
|
|
103
106
|
<UButton variant="soft" icon="i-lucide-file-down" @click="ui.openDocumentImport()">
|
|
104
107
|
{{ t('documents.templates.importButton') }}
|
|
105
108
|
</UButton>
|
|
106
|
-
</
|
|
109
|
+
</EmptyState>
|
|
107
110
|
|
|
108
111
|
<template v-else>
|
|
109
112
|
<UFormField :label="t('documents.templates.kindLabel')">
|
|
@@ -136,7 +139,7 @@ async function unlink(doc: SourceDocument) {
|
|
|
136
139
|
</p>
|
|
137
140
|
<div
|
|
138
141
|
v-if="template"
|
|
139
|
-
class="mt-2 flex items-center justify-between gap-2 rounded-md bg-
|
|
142
|
+
class="mt-2 flex items-center justify-between gap-2 rounded-md bg-elevated/70 px-3 py-2"
|
|
140
143
|
>
|
|
141
144
|
<DocumentOriginLink
|
|
142
145
|
:url="template.url"
|
|
@@ -173,7 +176,7 @@ async function unlink(doc: SourceDocument) {
|
|
|
173
176
|
<div
|
|
174
177
|
v-for="doc in exemplars"
|
|
175
178
|
:key="`${doc.source}:${doc.externalId}`"
|
|
176
|
-
class="flex items-center justify-between gap-2 rounded-md bg-
|
|
179
|
+
class="flex items-center justify-between gap-2 rounded-md bg-elevated/70 px-3 py-2"
|
|
177
180
|
>
|
|
178
181
|
<DocumentOriginLink
|
|
179
182
|
:url="doc.url"
|
|
@@ -194,9 +197,12 @@ async function unlink(doc: SourceDocument) {
|
|
|
194
197
|
</UButton>
|
|
195
198
|
</div>
|
|
196
199
|
</div>
|
|
197
|
-
<
|
|
198
|
-
|
|
199
|
-
|
|
200
|
+
<EmptyState
|
|
201
|
+
v-else
|
|
202
|
+
compact
|
|
203
|
+
icon="i-lucide-files"
|
|
204
|
+
:title="t('documents.templates.exemplarsEmpty')"
|
|
205
|
+
/>
|
|
200
206
|
</section>
|
|
201
207
|
|
|
202
208
|
<!-- Picker: choose an imported document, then set as template or add as example. -->
|
|
@@ -232,8 +232,8 @@ onMounted(() => {
|
|
|
232
232
|
<div v-if="fileMode === 'search'" class="space-y-2">
|
|
233
233
|
<UInput
|
|
234
234
|
v-model="fileQuery"
|
|
235
|
-
|
|
236
|
-
:
|
|
235
|
+
icon="i-lucide-file-search"
|
|
236
|
+
:loading="loadingFiles"
|
|
237
237
|
size="sm"
|
|
238
238
|
class="w-full"
|
|
239
239
|
:placeholder="t('documents.repoPicker.searchFilesPlaceholder')"
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { isDesignSource } from '@cat-factory/contracts'
|
|
3
3
|
import type { DocumentBoardPlan } from '~/types/domain'
|
|
4
|
+
import Spinner from '~/components/common/Spinner.vue'
|
|
4
5
|
|
|
5
6
|
// Preview the structure an imported document expands into, then spawn it. The
|
|
6
7
|
// plan is fetched fresh on open; a badge makes clear whether an LLM or the
|
|
@@ -16,7 +17,7 @@ const { t } = useI18n()
|
|
|
16
17
|
const ui = useUiStore()
|
|
17
18
|
const board = useBoardStore()
|
|
18
19
|
const documents = useDocumentsStore()
|
|
19
|
-
const
|
|
20
|
+
const actionToast = useActionToast()
|
|
20
21
|
const { present } = usePipelineErrorToast()
|
|
21
22
|
|
|
22
23
|
/** Design documents are planned into an existing service; prose documents at the board root. */
|
|
@@ -102,16 +103,13 @@ async function spawn() {
|
|
|
102
103
|
modules: t('documents.spawn.moduleCount', { count: result.modules }, result.modules),
|
|
103
104
|
tasks: t('documents.spawn.taskCount', { count: result.tasks }, result.tasks),
|
|
104
105
|
})
|
|
105
|
-
|
|
106
|
-
title: t('documents.spawn.spawned'),
|
|
106
|
+
actionToast.success('documents.spawn.spawned', {
|
|
107
107
|
// A reused module is stated only when there was one, and never folded into the created
|
|
108
108
|
// count: a spawn into a service that already had every planned module otherwise reports
|
|
109
109
|
// "0 modules" beside its tasks, which reads as the modules having failed.
|
|
110
110
|
description: result.reusedModules
|
|
111
111
|
? `${summary} · ${t('documents.spawn.reusedCount', { count: result.reusedModules }, result.reusedModules)}`
|
|
112
112
|
: summary,
|
|
113
|
-
icon: 'i-lucide-check',
|
|
114
|
-
color: 'success',
|
|
115
113
|
})
|
|
116
114
|
ui.closeSpawnPreview()
|
|
117
115
|
ui.closeDocumentImport()
|
|
@@ -168,7 +166,7 @@ async function spawn() {
|
|
|
168
166
|
</p>
|
|
169
167
|
|
|
170
168
|
<div v-if="loadingPlan" class="flex items-center gap-2 text-sm text-muted">
|
|
171
|
-
<
|
|
169
|
+
<Spinner class="h-4 w-4" />
|
|
172
170
|
{{ t('documents.spawn.buildingPlan') }}
|
|
173
171
|
</div>
|
|
174
172
|
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
// render identically. For a designer that widening IS the defect, not a detail.
|
|
21
21
|
import { refRowFor, classifyRefFailure, type RefState } from './ContextDocumentPicker.logic'
|
|
22
22
|
import type { DocumentSourceKind, ResolvedDocumentRef } from '~/types/domain'
|
|
23
|
+
import Spinner from '~/components/common/Spinner.vue'
|
|
23
24
|
|
|
24
25
|
const { t } = useI18n()
|
|
25
26
|
const ui = useUiStore()
|
|
@@ -178,7 +179,7 @@ function stage() {
|
|
|
178
179
|
v-if="state.status === 'checking'"
|
|
179
180
|
class="flex items-center gap-2 text-sm text-muted"
|
|
180
181
|
>
|
|
181
|
-
<
|
|
182
|
+
<Spinner class="h-4 w-4" />
|
|
182
183
|
{{ t('documents.startFromDesign.checking') }}
|
|
183
184
|
</div>
|
|
184
185
|
|
|
@@ -6,6 +6,7 @@ import ContextDocumentPicker from '~/components/documents/ContextDocumentPicker.
|
|
|
6
6
|
import DocumentOriginLink from '~/components/documents/DocumentOriginLink.vue'
|
|
7
7
|
import DocumentSyncState from '~/components/documents/DocumentSyncState.vue'
|
|
8
8
|
import InspectorSection from '~/components/panels/inspector/InspectorSection.vue'
|
|
9
|
+
import EmptyState from '~/components/common/EmptyState.vue'
|
|
9
10
|
|
|
10
11
|
// Documents (from any source) attached to a task OR an initiative as agent
|
|
11
12
|
// context, shown inside the InspectorPanel. An initiative takes the same
|
|
@@ -26,7 +27,7 @@ const props = defineProps<{ block: Block }>()
|
|
|
26
27
|
const { t } = useI18n()
|
|
27
28
|
const documents = useDocumentsStore()
|
|
28
29
|
const ui = useUiStore()
|
|
29
|
-
const
|
|
30
|
+
const actionToast = useActionToast()
|
|
30
31
|
const { linkPending, presentLinkFailures } = useContextLinking()
|
|
31
32
|
|
|
32
33
|
onMounted(() => {
|
|
@@ -88,7 +89,7 @@ async function attach(item: PendingContext) {
|
|
|
88
89
|
try {
|
|
89
90
|
const failures = await linkPending(props.block.id, [item])
|
|
90
91
|
if (failures.length) presentLinkFailures(failures, props.block.id)
|
|
91
|
-
else
|
|
92
|
+
else actionToast.success('documents.taskDocs.attached')
|
|
92
93
|
} finally {
|
|
93
94
|
linking.value = false
|
|
94
95
|
}
|
|
@@ -165,8 +166,6 @@ async function attach(item: PendingContext) {
|
|
|
165
166
|
<DocumentSyncState :doc="doc" class="mt-1" />
|
|
166
167
|
</div>
|
|
167
168
|
</div>
|
|
168
|
-
<
|
|
169
|
-
{{ emptyHint }}
|
|
170
|
-
</p>
|
|
169
|
+
<EmptyState v-else compact icon="i-lucide-file-text" :title="emptyHint" />
|
|
171
170
|
</InspectorSection>
|
|
172
171
|
</template>
|
|
@@ -10,6 +10,8 @@ import {
|
|
|
10
10
|
showsProviderFailure,
|
|
11
11
|
} from '~/components/environments/EnvironmentStatusPanel.logic'
|
|
12
12
|
import SectionLabel from '~/components/common/SectionLabel.vue'
|
|
13
|
+
import Spinner from '~/components/common/Spinner.vue'
|
|
14
|
+
import EmptyState from '~/components/common/EmptyState.vue'
|
|
13
15
|
|
|
14
16
|
const props = defineProps<{
|
|
15
17
|
environment: RunEnvironment | null
|
|
@@ -112,13 +114,11 @@ const envInTransition = computed(
|
|
|
112
114
|
</SectionLabel>
|
|
113
115
|
<div v-if="environment" class="space-y-2">
|
|
114
116
|
<div class="flex items-center gap-2 text-sm">
|
|
115
|
-
<
|
|
117
|
+
<Spinner
|
|
116
118
|
:name="ENV_STATUS_META[environment.status].icon"
|
|
119
|
+
:spinning="runActive && envInTransition"
|
|
117
120
|
class="h-3.5 w-3.5"
|
|
118
|
-
:class="[
|
|
119
|
-
ENV_STATUS_META[environment.status].color,
|
|
120
|
-
{ 'animate-spin': runActive && envInTransition },
|
|
121
|
-
]"
|
|
121
|
+
:class="ENV_STATUS_META[environment.status].color"
|
|
122
122
|
/>
|
|
123
123
|
<span :class="ENV_STATUS_META[environment.status].color">{{
|
|
124
124
|
ENV_STATUS_META[environment.status].label
|
|
@@ -166,8 +166,11 @@ const envInTransition = computed(
|
|
|
166
166
|
{{ t('environments.statusNote', { note: statusNote }) }}
|
|
167
167
|
</p>
|
|
168
168
|
</div>
|
|
169
|
-
<
|
|
170
|
-
|
|
171
|
-
|
|
169
|
+
<EmptyState
|
|
170
|
+
v-else
|
|
171
|
+
compact
|
|
172
|
+
icon="i-lucide-server"
|
|
173
|
+
:title="degradedReason ?? t('environments.empty')"
|
|
174
|
+
/>
|
|
172
175
|
</section>
|
|
173
176
|
</template>
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
// advances to the review step. Rendered by `JourneyOutlet`, so it receives the
|
|
6
6
|
// `ModuleEntryProps` (`input` / `exit` / `goBack`) as attributes.
|
|
7
7
|
import type { EnvSelectOutput } from '~/modular/journeys/environmentSetup.logic'
|
|
8
|
+
import EmptyState from '~/components/common/EmptyState.vue'
|
|
8
9
|
|
|
9
10
|
defineProps<{
|
|
10
11
|
input: { frameId: string | null }
|
|
@@ -21,9 +22,12 @@ const { t } = useI18n()
|
|
|
21
22
|
<!-- The one-service scope caveat, stated on the step that asks for the service: nothing
|
|
22
23
|
here changes any other service, and running it twice just re-edits this one's recipe. -->
|
|
23
24
|
<p class="text-xs leading-relaxed text-dimmed">{{ t('environmentWizard.pick.scope') }}</p>
|
|
24
|
-
<
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
<EmptyState
|
|
26
|
+
v-if="!store.serviceFrames.length"
|
|
27
|
+
compact
|
|
28
|
+
icon="i-lucide-box"
|
|
29
|
+
:title="t('environmentWizard.pick.empty')"
|
|
30
|
+
/>
|
|
27
31
|
<div v-else class="space-y-1.5">
|
|
28
32
|
<UButton
|
|
29
33
|
v-for="frame in store.serviceFrames"
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
import { computed } from 'vue'
|
|
7
7
|
import JourneyStepNav from '~/components/environments/steps/JourneyStepNav.vue'
|
|
8
8
|
import { useEnvironmentWizardTarget } from '~/modular/journeys/environmentSetup.frame'
|
|
9
|
+
import EmptyState from '~/components/common/EmptyState.vue'
|
|
9
10
|
|
|
10
11
|
const props = defineProps<{
|
|
11
12
|
input: { frameId: string | null }
|
|
@@ -48,13 +49,13 @@ const PREFLIGHT_COLOR: Record<'pass' | 'warn' | 'fail', 'success' | 'warning' |
|
|
|
48
49
|
</UButton>
|
|
49
50
|
</div>
|
|
50
51
|
|
|
51
|
-
<
|
|
52
|
+
<EmptyState
|
|
52
53
|
v-if="!store.recipe.prerequisites?.length"
|
|
53
|
-
|
|
54
|
+
compact
|
|
55
|
+
icon="i-lucide-list-checks"
|
|
56
|
+
:title="t('environmentWizard.preflight.none')"
|
|
54
57
|
data-testid="env-setup-preflight-none"
|
|
55
|
-
|
|
56
|
-
{{ t('environmentWizard.preflight.none') }}
|
|
57
|
-
</p>
|
|
58
|
+
/>
|
|
58
59
|
<p
|
|
59
60
|
v-else-if="preflightsUnavailable"
|
|
60
61
|
class="text-xs text-app-warning-300/80"
|
|
@@ -7,6 +7,7 @@ import PipelineProgress from '~/components/pipeline/PipelineProgress.vue'
|
|
|
7
7
|
import IconButton from '~/components/common/IconButton.vue'
|
|
8
8
|
import { useInitiativePlanning } from '~/composables/useInitiativePlanning'
|
|
9
9
|
import SectionLabel from '~/components/common/SectionLabel.vue'
|
|
10
|
+
import EmptyState from '~/components/common/EmptyState.vue'
|
|
10
11
|
|
|
11
12
|
const board = useBoardStore()
|
|
12
13
|
const pipelines = usePipelinesStore()
|
|
@@ -214,12 +215,12 @@ function openApprovalFor(approvalId: string) {
|
|
|
214
215
|
@open-approval="openApprovalFor"
|
|
215
216
|
/>
|
|
216
217
|
|
|
217
|
-
<
|
|
218
|
+
<EmptyState
|
|
218
219
|
v-else
|
|
219
|
-
class="flex
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
220
|
+
class="flex-1"
|
|
221
|
+
icon="i-lucide-workflow"
|
|
222
|
+
:title="t('focus.emptyPipelineHint')"
|
|
223
|
+
/>
|
|
223
224
|
</section>
|
|
224
225
|
|
|
225
226
|
<!-- side: details -->
|
|
@@ -13,6 +13,7 @@ import { useFollowUpsStore } from '~/stores/followUps'
|
|
|
13
13
|
import type { FollowUpItem, FollowUpResolution } from '~/types/execution'
|
|
14
14
|
import { FOLLOW_UP_COMPANION_META } from '~/utils/catalog'
|
|
15
15
|
import ResultWindowShell from '~/components/panels/ResultWindowShell.vue'
|
|
16
|
+
import EmptyState from '~/components/common/EmptyState.vue'
|
|
16
17
|
|
|
17
18
|
const execution = useExecutionStore()
|
|
18
19
|
const board = useBoardStore()
|
|
@@ -156,16 +157,13 @@ function hasRecordedAnswer(item: FollowUpItem): boolean {
|
|
|
156
157
|
|
|
157
158
|
<div class="min-h-0 flex-1 overflow-y-auto px-5 py-4">
|
|
158
159
|
<!-- Empty -->
|
|
159
|
-
<
|
|
160
|
+
<EmptyState
|
|
160
161
|
v-if="items.length === 0"
|
|
161
|
-
class="
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
{{ t('followUp.empty.hint') }}
|
|
167
|
-
</p>
|
|
168
|
-
</div>
|
|
162
|
+
class="h-full"
|
|
163
|
+
:icon="FOLLOW_UP_COMPANION_META.icon"
|
|
164
|
+
:title="t('followUp.empty.title')"
|
|
165
|
+
:description="t('followUp.empty.hint')"
|
|
166
|
+
/>
|
|
169
167
|
|
|
170
168
|
<div v-else class="space-y-3">
|
|
171
169
|
<p
|
|
@@ -15,6 +15,8 @@ import { useForkDecisionStore } from '~/stores/forkDecision'
|
|
|
15
15
|
import type { ForkChatMessage, ForkDecisionStepState, ForkOption } from '~/types/execution'
|
|
16
16
|
import { FORK_DECISION_META } from '~/utils/catalog'
|
|
17
17
|
import ResultWindowShell from '~/components/panels/ResultWindowShell.vue'
|
|
18
|
+
import Spinner from '~/components/common/Spinner.vue'
|
|
19
|
+
import EmptyState from '~/components/common/EmptyState.vue'
|
|
18
20
|
|
|
19
21
|
const execution = useExecutionStore()
|
|
20
22
|
const board = useBoardStore()
|
|
@@ -170,7 +172,7 @@ const { requestClose } = useUnsavedGuard({
|
|
|
170
172
|
v-if="status === 'proposing'"
|
|
171
173
|
class="flex h-full flex-col items-center justify-center gap-2 py-10 text-center text-muted"
|
|
172
174
|
>
|
|
173
|
-
<
|
|
175
|
+
<Spinner class="h-8 w-8 opacity-60" />
|
|
174
176
|
<p class="text-sm">{{ t('forkDecision.proposing.title') }}</p>
|
|
175
177
|
<p class="max-w-sm text-2xs text-dimmed">
|
|
176
178
|
{{ t('forkDecision.proposing.hint') }}
|
|
@@ -322,7 +324,7 @@ const { requestClose } = useUnsavedGuard({
|
|
|
322
324
|
<p
|
|
323
325
|
class="flex items-center gap-1.5 rounded-lg bg-elevated/70 px-3 py-1.5 text-xs text-muted"
|
|
324
326
|
>
|
|
325
|
-
<
|
|
327
|
+
<Spinner class="h-3.5 w-3.5" />
|
|
326
328
|
{{ t('forkDecision.chat.thinking') }}
|
|
327
329
|
</p>
|
|
328
330
|
</div>
|
|
@@ -364,13 +366,12 @@ const { requestClose } = useUnsavedGuard({
|
|
|
364
366
|
</div>
|
|
365
367
|
|
|
366
368
|
<!-- Skipped / no state: nothing to decide. -->
|
|
367
|
-
<
|
|
369
|
+
<EmptyState
|
|
368
370
|
v-else
|
|
369
|
-
class="
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
</div>
|
|
371
|
+
class="h-full"
|
|
372
|
+
:icon="FORK_DECISION_META.icon"
|
|
373
|
+
:title="t('forkDecision.empty.title')"
|
|
374
|
+
/>
|
|
374
375
|
</div>
|
|
375
376
|
|
|
376
377
|
<footer
|
|
@@ -20,9 +20,10 @@ import type { ApiContractFormat, FoundationalServiceTier } from '~/types/domain'
|
|
|
20
20
|
import { useFoundationalServicesStore } from '~/stores/foundationalServices'
|
|
21
21
|
import FoundationalContractSummary from '~/components/foundational/FoundationalContractSummary.vue'
|
|
22
22
|
import IconButton from '~/components/common/IconButton.vue'
|
|
23
|
+
import EmptyState from '~/components/common/EmptyState.vue'
|
|
23
24
|
|
|
24
25
|
const catalog = useFoundationalServicesStore()
|
|
25
|
-
const
|
|
26
|
+
const actionToast = useActionToast()
|
|
26
27
|
const { present } = usePipelineErrorToast()
|
|
27
28
|
const { t } = useI18n()
|
|
28
29
|
|
|
@@ -71,7 +72,7 @@ async function suppress(serviceId: string) {
|
|
|
71
72
|
await withRow(`suppress:${serviceId}`, async () => {
|
|
72
73
|
try {
|
|
73
74
|
await catalog.suppress(serviceId)
|
|
74
|
-
|
|
75
|
+
actionToast.success('foundational.toast.suppressed')
|
|
75
76
|
} catch (e) {
|
|
76
77
|
present(e, 'foundational.toast.suppressFailed')
|
|
77
78
|
}
|
|
@@ -156,8 +157,11 @@ async function suppress(serviceId: string) {
|
|
|
156
157
|
</div>
|
|
157
158
|
</div>
|
|
158
159
|
|
|
159
|
-
<
|
|
160
|
-
|
|
161
|
-
|
|
160
|
+
<EmptyState
|
|
161
|
+
v-if="!catalog.resolved.length"
|
|
162
|
+
compact
|
|
163
|
+
icon="i-lucide-package"
|
|
164
|
+
:title="t('foundational.catalog.empty')"
|
|
165
|
+
/>
|
|
162
166
|
</div>
|
|
163
167
|
</template>
|
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
} from '~/stores/foundationalServices'
|
|
22
22
|
import FoundationalContractSummary from '~/components/foundational/FoundationalContractSummary.vue'
|
|
23
23
|
import IconButton from '~/components/common/IconButton.vue'
|
|
24
|
+
import EmptyState from '~/components/common/EmptyState.vue'
|
|
24
25
|
|
|
25
26
|
const props = defineProps<{ kind: FoundationalServiceOwnerKind; ownerId: string }>()
|
|
26
27
|
|
|
@@ -28,7 +29,7 @@ const catalog =
|
|
|
28
29
|
props.kind === 'workspace'
|
|
29
30
|
? useFoundationalServicesStore()
|
|
30
31
|
: useFoundationalServices(props.kind, props.ownerId)
|
|
31
|
-
const
|
|
32
|
+
const actionToast = useActionToast()
|
|
32
33
|
const { present } = usePipelineErrorToast()
|
|
33
34
|
const { t } = useI18n()
|
|
34
35
|
const { confirm } = useConfirm()
|
|
@@ -131,7 +132,7 @@ async function save() {
|
|
|
131
132
|
capabilities: capabilityList.value,
|
|
132
133
|
...(contracts ? { contracts } : {}),
|
|
133
134
|
})
|
|
134
|
-
|
|
135
|
+
actionToast.success('foundational.toast.created')
|
|
135
136
|
} else {
|
|
136
137
|
await catalog.update(draft.id, {
|
|
137
138
|
name: draft.name.trim(),
|
|
@@ -140,7 +141,7 @@ async function save() {
|
|
|
140
141
|
capabilities: capabilityList.value,
|
|
141
142
|
...(contracts ? { contracts } : {}),
|
|
142
143
|
})
|
|
143
|
-
|
|
144
|
+
actionToast.success('foundational.toast.updated')
|
|
144
145
|
}
|
|
145
146
|
editing.value = null
|
|
146
147
|
} catch (e) {
|
|
@@ -171,7 +172,7 @@ async function remove(service: FoundationalService) {
|
|
|
171
172
|
if (!ok) return
|
|
172
173
|
try {
|
|
173
174
|
await catalog.remove(service.id)
|
|
174
|
-
|
|
175
|
+
actionToast.success('foundational.toast.deleted')
|
|
175
176
|
} catch (e) {
|
|
176
177
|
present(e, 'foundational.toast.deleteFailed')
|
|
177
178
|
}
|
|
@@ -224,9 +225,12 @@ async function remove(service: FoundationalService) {
|
|
|
224
225
|
</div>
|
|
225
226
|
</div>
|
|
226
227
|
</div>
|
|
227
|
-
<
|
|
228
|
-
|
|
229
|
-
|
|
228
|
+
<EmptyState
|
|
229
|
+
v-if="!catalog.services.length"
|
|
230
|
+
compact
|
|
231
|
+
icon="i-lucide-package"
|
|
232
|
+
:title="t('foundational.registry.empty')"
|
|
233
|
+
/>
|
|
230
234
|
|
|
231
235
|
<UButton
|
|
232
236
|
v-if="editing === null"
|
|
@@ -28,6 +28,7 @@ import {
|
|
|
28
28
|
import GitHubRepoSearchSelect from '~/components/github/GitHubRepoSearchSelect.vue'
|
|
29
29
|
import RepoTreeBrowser from '~/components/github/RepoTreeBrowser.vue'
|
|
30
30
|
import IconButton from '~/components/common/IconButton.vue'
|
|
31
|
+
import EmptyState from '~/components/common/EmptyState.vue'
|
|
31
32
|
|
|
32
33
|
const props = defineProps<{ kind: FoundationalServiceOwnerKind; ownerId: string }>()
|
|
33
34
|
|
|
@@ -36,7 +37,7 @@ const catalog =
|
|
|
36
37
|
? useFoundationalServicesStore()
|
|
37
38
|
: useFoundationalServices(props.kind, props.ownerId)
|
|
38
39
|
const github = useGitHubStore()
|
|
39
|
-
const
|
|
40
|
+
const actionToast = useActionToast()
|
|
40
41
|
const { present } = usePipelineErrorToast()
|
|
41
42
|
const { t, d } = useI18n()
|
|
42
43
|
const { confirm } = useConfirm()
|
|
@@ -163,7 +164,7 @@ async function link() {
|
|
|
163
164
|
: {}),
|
|
164
165
|
})
|
|
165
166
|
resetDraft()
|
|
166
|
-
|
|
167
|
+
actionToast.success('foundational.toast.sourceLinked')
|
|
167
168
|
return result
|
|
168
169
|
} catch (e) {
|
|
169
170
|
present(e, 'foundational.toast.linkSourceFailed')
|
|
@@ -185,17 +186,14 @@ async function sync(id: string) {
|
|
|
185
186
|
)
|
|
186
187
|
const coverage = result.folderScan ? folderScanNotes.value[result.folderScan] : null
|
|
187
188
|
if (coverage) notes.push(coverage)
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
}),
|
|
189
|
+
// A folder we could not fully see, or could not find at all, is the one sync outcome a
|
|
190
|
+
// human has to act on: the counts alone would read as an ordinary quiet success.
|
|
191
|
+
const synced = {
|
|
192
|
+
params: { updated: result.upserted, removed: result.tombstoned },
|
|
193
193
|
...(notes.length ? { description: notes.join(' ') } : {}),
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
color: coverage ? 'warning' : 'info',
|
|
198
|
-
})
|
|
194
|
+
}
|
|
195
|
+
if (coverage) actionToast.warning('foundational.toast.synced', synced)
|
|
196
|
+
else actionToast.success('foundational.toast.synced', synced)
|
|
199
197
|
} catch (e) {
|
|
200
198
|
present(e, 'foundational.toast.syncFailed')
|
|
201
199
|
}
|
|
@@ -206,12 +204,9 @@ async function check(id: string) {
|
|
|
206
204
|
await withRow(`check:${id}`, async () => {
|
|
207
205
|
try {
|
|
208
206
|
const status = await catalog.checkSource(id)
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
: t('foundational.toast.upToDate'),
|
|
213
|
-
icon: status.changed ? 'i-lucide-bell-dot' : 'i-lucide-check',
|
|
214
|
-
})
|
|
207
|
+
actionToast.info(
|
|
208
|
+
status.changed ? 'foundational.toast.changesAvailable' : 'foundational.toast.upToDate',
|
|
209
|
+
)
|
|
215
210
|
} catch (e) {
|
|
216
211
|
present(e, 'foundational.toast.checkSourceFailed')
|
|
217
212
|
}
|
|
@@ -233,7 +228,7 @@ async function unlink(id: string) {
|
|
|
233
228
|
await withRow(`unlink:${id}`, async () => {
|
|
234
229
|
try {
|
|
235
230
|
await catalog.unlinkSource(id)
|
|
236
|
-
|
|
231
|
+
actionToast.success('foundational.toast.sourceUnlinked')
|
|
237
232
|
} catch (e) {
|
|
238
233
|
present(e, 'foundational.toast.unlinkSourceFailed')
|
|
239
234
|
}
|
|
@@ -325,9 +320,12 @@ async function unlink(id: string) {
|
|
|
325
320
|
/>
|
|
326
321
|
</div>
|
|
327
322
|
</div>
|
|
328
|
-
<
|
|
329
|
-
|
|
330
|
-
|
|
323
|
+
<EmptyState
|
|
324
|
+
v-if="!catalog.sources.length"
|
|
325
|
+
compact
|
|
326
|
+
icon="i-lucide-git-branch"
|
|
327
|
+
:title="t('foundational.sources.empty')"
|
|
328
|
+
/>
|
|
331
329
|
|
|
332
330
|
<!-- Linking needs the GitHub integration; say so rather than offering a form that 503s. -->
|
|
333
331
|
<div
|