@shepai/cli 1.47.0 → 1.48.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/apis/json-schema/ApprovalGateDefaults.yaml +26 -0
- package/apis/json-schema/Feature.yaml +3 -0
- package/apis/json-schema/Repository.yaml +16 -0
- package/apis/json-schema/Settings.yaml +5 -0
- package/apis/json-schema/WorkflowConfig.yaml +4 -20
- package/dist/packages/core/src/application/ports/output/services/git-pr-service.interface.d.ts +17 -0
- package/dist/packages/core/src/application/ports/output/services/git-pr-service.interface.d.ts.map +1 -1
- package/dist/packages/core/src/application/ports/output/services/worktree-service.interface.d.ts +11 -1
- package/dist/packages/core/src/application/ports/output/services/worktree-service.interface.d.ts.map +1 -1
- package/dist/packages/core/src/application/use-cases/features/create/create-feature.use-case.d.ts +3 -1
- package/dist/packages/core/src/application/use-cases/features/create/create-feature.use-case.d.ts.map +1 -1
- package/dist/packages/core/src/application/use-cases/features/create/create-feature.use-case.js +11 -4
- package/dist/packages/core/src/application/use-cases/features/get-plan-artifact.use-case.d.ts +19 -0
- package/dist/packages/core/src/application/use-cases/features/get-plan-artifact.use-case.d.ts.map +1 -0
- package/dist/packages/core/src/application/use-cases/features/get-plan-artifact.use-case.js +52 -0
- package/dist/packages/core/src/infrastructure/di/container.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/di/container.js +5 -0
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-worker.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-worker.js +2 -0
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/merge.node.d.ts +2 -0
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/merge.node.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/merge.node.js +10 -3
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/prompts/merge-prompts.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/prompts/merge-prompts.js +15 -7
- package/dist/packages/core/src/infrastructure/services/git/git-pr.service.d.ts +2 -0
- package/dist/packages/core/src/infrastructure/services/git/git-pr.service.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/git/git-pr.service.js +41 -0
- package/dist/packages/core/src/infrastructure/services/git/worktree.service.d.ts +2 -1
- package/dist/packages/core/src/infrastructure/services/git/worktree.service.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/git/worktree.service.js +29 -4
- package/dist/src/presentation/cli/ui/messages.d.ts.map +1 -1
- package/dist/src/presentation/cli/ui/messages.js +1 -7
- package/dist/src/presentation/web/app/actions/get-merge-review-data.d.ts +7 -0
- package/dist/src/presentation/web/app/actions/get-merge-review-data.d.ts.map +1 -0
- package/dist/src/presentation/web/app/actions/get-merge-review-data.js +49 -0
- package/dist/src/presentation/web/app/page.d.ts.map +1 -1
- package/dist/src/presentation/web/app/page.js +1 -0
- package/dist/src/presentation/web/components/common/feature-node/feature-node.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/feature-node/feature-node.js +8 -1
- package/dist/src/presentation/web/components/common/feature-node/feature-node.stories.d.ts +1 -0
- package/dist/src/presentation/web/components/common/feature-node/feature-node.stories.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/feature-node/feature-node.stories.js +22 -1
- package/dist/src/presentation/web/components/common/merge-review/index.d.ts +4 -0
- package/dist/src/presentation/web/components/common/merge-review/index.d.ts.map +1 -0
- package/dist/src/presentation/web/components/common/merge-review/index.js +2 -0
- package/dist/src/presentation/web/components/common/merge-review/merge-review-config.d.ts +75 -0
- package/dist/src/presentation/web/components/common/merge-review/merge-review-config.d.ts.map +1 -0
- package/dist/src/presentation/web/components/common/merge-review/merge-review-config.js +1 -0
- package/dist/src/presentation/web/components/common/merge-review/merge-review-drawer.d.ts +3 -0
- package/dist/src/presentation/web/components/common/merge-review/merge-review-drawer.d.ts.map +1 -0
- package/dist/src/presentation/web/components/common/merge-review/merge-review-drawer.js +7 -0
- package/dist/src/presentation/web/components/common/merge-review/merge-review.d.ts +3 -0
- package/dist/src/presentation/web/components/common/merge-review/merge-review.d.ts.map +1 -0
- package/dist/src/presentation/web/components/common/merge-review/merge-review.js +36 -0
- package/dist/src/presentation/web/components/common/merge-review/merge-review.stories.d.ts +32 -0
- package/dist/src/presentation/web/components/common/merge-review/merge-review.stories.d.ts.map +1 -0
- package/dist/src/presentation/web/components/common/merge-review/merge-review.stories.js +165 -0
- package/dist/src/presentation/web/components/features/control-center/control-center-inner.d.ts.map +1 -1
- package/dist/src/presentation/web/components/features/control-center/control-center-inner.js +55 -1
- package/dist/src/presentation/web/components/features/control-center/control-center.stories.d.ts.map +1 -1
- package/dist/src/presentation/web/components/features/control-center/control-center.stories.js +15 -0
- package/dist/src/presentation/web/components/features/control-center/use-control-center-state.d.ts.map +1 -1
- package/dist/src/presentation/web/components/features/control-center/use-control-center-state.js +37 -15
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/web/.next/BUILD_ID +1 -1
- package/web/.next/build-manifest.json +2 -2
- package/web/.next/cache/.previewinfo +1 -1
- package/web/.next/cache/.rscinfo +1 -1
- package/web/.next/cache/.tsbuildinfo +1 -1
- package/web/.next/cache/config.json +3 -3
- package/web/.next/fallback-build-manifest.json +2 -2
- package/web/.next/prerender-manifest.json +3 -3
- package/web/.next/required-server-files.js +1 -1
- package/web/.next/required-server-files.json +1 -1
- package/web/.next/server/app/_global-error.html +2 -2
- package/web/.next/server/app/_global-error.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/web/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/page/server-reference-manifest.json +39 -24
- package/web/.next/server/app/page.js +1 -1
- package/web/.next/server/app/page.js.nft.json +1 -1
- package/web/.next/server/app/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/version/page.js.nft.json +1 -1
- package/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__03a0dba7._.js +4 -4
- package/web/.next/server/chunks/ssr/[root-of-the-server]__03a0dba7._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__19d52794._.js +9 -0
- package/web/.next/server/chunks/ssr/[root-of-the-server]__19d52794._.js.map +1 -0
- package/web/.next/server/chunks/ssr/[root-of-the-server]__249c74f6._.js +1 -1
- package/web/.next/{standalone/src/presentation/web/.next/server/chunks/ssr/_3ac3601c._.js → server/chunks/ssr/_1fafa9db._.js} +2 -2
- package/web/.next/server/chunks/ssr/_1fafa9db._.js.map +1 -0
- package/web/.next/server/chunks/ssr/src_presentation_web_components_e599bb8c._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_e599bb8c._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_ed0934e5._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_ed0934e5._.js.map +1 -1
- package/web/.next/server/pages/500.html +2 -2
- package/web/.next/server/server-reference-manifest.js +1 -1
- package/web/.next/server/server-reference-manifest.json +40 -25
- package/web/.next/standalone/src/presentation/web/.next/BUILD_ID +1 -1
- package/web/.next/standalone/src/presentation/web/.next/build-manifest.json +2 -2
- package/web/.next/standalone/src/presentation/web/.next/prerender-manifest.json +3 -3
- package/web/.next/standalone/src/presentation/web/.next/required-server-files.json +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.html +2 -2
- package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.rsc +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/page/server-reference-manifest.json +39 -24
- package/web/.next/standalone/src/presentation/web/.next/server/app/page.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/page.js.nft.json +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/version/page.js.nft.json +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__03a0dba7._.js +4 -4
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__19d52794._.js +9 -0
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__249c74f6._.js +1 -1
- package/web/.next/{server/chunks/ssr/_3ac3601c._.js → standalone/src/presentation/web/.next/server/chunks/ssr/_1fafa9db._.js} +2 -2
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_components_e599bb8c._.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_ed0934e5._.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/pages/500.html +2 -2
- package/web/.next/standalone/src/presentation/web/.next/server/server-reference-manifest.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/server-reference-manifest.json +40 -25
- package/web/.next/standalone/src/presentation/web/app/actions/get-merge-review-data.ts +64 -0
- package/web/.next/standalone/src/presentation/web/app/page.tsx +1 -0
- package/web/.next/standalone/src/presentation/web/components/common/feature-node/feature-node.stories.tsx +23 -1
- package/web/.next/standalone/src/presentation/web/components/common/feature-node/feature-node.tsx +6 -1
- package/web/.next/standalone/src/presentation/web/components/common/merge-review/index.ts +7 -0
- package/web/.next/standalone/src/presentation/web/components/common/merge-review/merge-review-config.ts +81 -0
- package/web/.next/standalone/src/presentation/web/components/common/merge-review/merge-review-drawer.tsx +34 -0
- package/web/.next/standalone/src/presentation/web/components/common/merge-review/merge-review.stories.tsx +240 -0
- package/web/.next/standalone/src/presentation/web/components/common/merge-review/merge-review.tsx +252 -0
- package/web/.next/standalone/src/presentation/web/components/features/control-center/control-center-inner.tsx +82 -1
- package/web/.next/standalone/src/presentation/web/components/features/control-center/control-center.stories.tsx +15 -0
- package/web/.next/standalone/src/presentation/web/components/features/control-center/use-control-center-state.ts +47 -17
- package/web/.next/standalone/src/presentation/web/server.js +1 -1
- package/web/.next/static/chunks/{9f8e71029fb04681.js → 0da7a9860fa6ae05.js} +2 -2
- package/web/.next/static/chunks/22f30ce91a3c79c1.js +1 -0
- package/web/.next/static/chunks/66378a6c055c4e67.js +10 -0
- package/web/.next/static/chunks/8668962d3e682263.css +2 -0
- package/web/.next/trace +1 -1
- package/web/.next/trace-build +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__d6d75c22._.js +0 -9
- package/web/.next/server/chunks/ssr/[root-of-the-server]__d6d75c22._.js.map +0 -1
- package/web/.next/server/chunks/ssr/_3ac3601c._.js.map +0 -1
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__d6d75c22._.js +0 -9
- package/web/.next/static/chunks/779c99975c85389e.js +0 -10
- package/web/.next/static/chunks/83ff3b6bbee54bce.js +0 -1
- package/web/.next/static/chunks/b7b7abe79e05b229.css +0 -2
- /package/web/.next/static/{wQ3vPV9I8JeacVNyp4HFg → 1kZFDMQ0i-Y8dy1KkHlzv}/_buildManifest.js +0 -0
- /package/web/.next/static/{wQ3vPV9I8JeacVNyp4HFg → 1kZFDMQ0i-Y8dy1KkHlzv}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/static/{wQ3vPV9I8JeacVNyp4HFg → 1kZFDMQ0i-Y8dy1KkHlzv}/_ssgManifest.js +0 -0
package/dist/src/presentation/web/components/features/control-center/control-center-inner.js
CHANGED
|
@@ -6,10 +6,12 @@ import { approveFeature } from '../../../app/actions/approve-feature.js';
|
|
|
6
6
|
import { getFeatureArtifact } from '../../../app/actions/get-feature-artifact.js';
|
|
7
7
|
import { getResearchArtifact } from '../../../app/actions/get-research-artifact.js';
|
|
8
8
|
import { getWorkflowDefaults } from '../../../app/actions/get-workflow-defaults.js';
|
|
9
|
+
import { getMergeReviewData } from '../../../app/actions/get-merge-review-data.js';
|
|
9
10
|
import { FeaturesCanvas } from '../../features/features-canvas/index.js';
|
|
10
11
|
import { FeatureDrawer, FeatureCreateDrawer } from '../../common/index.js';
|
|
11
12
|
import { PrdQuestionnaireDrawer } from '../../common/prd-questionnaire/index.js';
|
|
12
13
|
import { TechDecisionsDrawer } from '../../common/tech-decisions-review/index.js';
|
|
14
|
+
import { MergeReviewDrawer } from '../../common/merge-review/index.js';
|
|
13
15
|
import { NotificationPermissionBanner } from '../../common/notification-permission-banner/index.js';
|
|
14
16
|
import { ControlCenterEmptyState } from './control-center-empty-state.js';
|
|
15
17
|
import { useControlCenterState } from './use-control-center-state.js';
|
|
@@ -32,8 +34,12 @@ export function ControlCenterInner({ initialNodes, initialEdges }) {
|
|
|
32
34
|
// Tech decisions drawer state
|
|
33
35
|
const [techDecisionsData, setTechDecisionsData] = useState(null);
|
|
34
36
|
const [isLoadingTechDecisions, setIsLoadingTechDecisions] = useState(false);
|
|
37
|
+
// Merge review drawer state
|
|
38
|
+
const [mergeReviewData, setMergeReviewData] = useState(null);
|
|
39
|
+
const [isLoadingMergeReview, setIsLoadingMergeReview] = useState(false);
|
|
35
40
|
const showPrdDrawer = selectedNode?.lifecycle === 'requirements' && selectedNode?.state === 'action-required';
|
|
36
41
|
const showTechDecisionsDrawer = selectedNode?.lifecycle === 'implementation' && selectedNode?.state === 'action-required';
|
|
42
|
+
const showMergeReviewDrawer = selectedNode?.lifecycle === 'review' && selectedNode?.state === 'action-required';
|
|
37
43
|
const handlePrdSelect = useCallback((questionId, optionId) => {
|
|
38
44
|
setPrdSelections((prev) => ({ ...prev, [questionId]: optionId }));
|
|
39
45
|
}, []);
|
|
@@ -75,6 +81,24 @@ export function ControlCenterInner({ initialNodes, initialEdges }) {
|
|
|
75
81
|
toast.success('Plan approved — agent resuming');
|
|
76
82
|
clearSelection();
|
|
77
83
|
}, [selectedNode?.featureId, clearSelection]);
|
|
84
|
+
const handleMergeApprove = useCallback(async () => {
|
|
85
|
+
const featureId = selectedNode?.featureId;
|
|
86
|
+
if (!featureId)
|
|
87
|
+
return;
|
|
88
|
+
const result = await approveFeature(featureId);
|
|
89
|
+
if (!result.approved) {
|
|
90
|
+
toast.error(result.error ?? 'Failed to approve merge');
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
toast.success('Merge approved — agent resuming');
|
|
94
|
+
clearSelection();
|
|
95
|
+
}, [selectedNode?.featureId, clearSelection]);
|
|
96
|
+
const handleMergeRefine = useCallback(async (_text) => {
|
|
97
|
+
setIsLoadingMergeReview(true);
|
|
98
|
+
// TODO: Call API to refine merge
|
|
99
|
+
await new Promise((resolve) => setTimeout(resolve, 1500));
|
|
100
|
+
setIsLoadingMergeReview(false);
|
|
101
|
+
}, []);
|
|
78
102
|
// Fetch questionnaire data and reset selections when a different feature is selected
|
|
79
103
|
const prdFeatureId = showPrdDrawer ? selectedNode?.featureId : null;
|
|
80
104
|
useEffect(() => {
|
|
@@ -148,6 +172,36 @@ export function ControlCenterInner({ initialNodes, initialEdges }) {
|
|
|
148
172
|
cancelled = true;
|
|
149
173
|
};
|
|
150
174
|
}, [techDecisionsFeatureId]);
|
|
175
|
+
// Fetch merge review data when a feature is in review + action-required
|
|
176
|
+
const mergeFeatureId = showMergeReviewDrawer ? selectedNode?.featureId : null;
|
|
177
|
+
useEffect(() => {
|
|
178
|
+
setMergeReviewData(null);
|
|
179
|
+
if (!mergeFeatureId)
|
|
180
|
+
return;
|
|
181
|
+
let cancelled = false;
|
|
182
|
+
setIsLoadingMergeReview(true);
|
|
183
|
+
getMergeReviewData(mergeFeatureId)
|
|
184
|
+
.then((result) => {
|
|
185
|
+
if (cancelled)
|
|
186
|
+
return;
|
|
187
|
+
if ('error' in result) {
|
|
188
|
+
toast.error(result.error);
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
setMergeReviewData(result);
|
|
192
|
+
})
|
|
193
|
+
.catch(() => {
|
|
194
|
+
if (!cancelled)
|
|
195
|
+
toast.error('Failed to load merge review data');
|
|
196
|
+
})
|
|
197
|
+
.finally(() => {
|
|
198
|
+
if (!cancelled)
|
|
199
|
+
setIsLoadingMergeReview(false);
|
|
200
|
+
});
|
|
201
|
+
return () => {
|
|
202
|
+
cancelled = true;
|
|
203
|
+
};
|
|
204
|
+
}, [mergeFeatureId]);
|
|
151
205
|
const hasRepositories = nodes.some((n) => n.type === 'repositoryNode');
|
|
152
206
|
// Listen for global "open create drawer" events from the sidebar
|
|
153
207
|
useEffect(() => {
|
|
@@ -158,5 +212,5 @@ export function ControlCenterInner({ initialNodes, initialEdges }) {
|
|
|
158
212
|
if (!hasRepositories) {
|
|
159
213
|
return (_jsxs(_Fragment, { children: [_jsx(NotificationPermissionBanner, {}), _jsx(ControlCenterEmptyState, { onRepositorySelect: handleAddRepository }), _jsx(FeatureCreateDrawer, { open: isCreateDrawerOpen, onClose: closeCreateDrawer, onSubmit: handleCreateFeatureSubmit, repositoryPath: pendingRepositoryPath, workflowDefaults: workflowDefaults })] }));
|
|
160
214
|
}
|
|
161
|
-
return (_jsxs(_Fragment, { children: [_jsx(NotificationPermissionBanner, {}), _jsx(FeaturesCanvas, { nodes: nodes, edges: edges, onNodesChange: onNodesChange, onConnect: handleConnect, onAddFeature: handleAddFeature, onNodeAction: handleAddFeatureToFeature, onNodeClick: handleNodeClick, onPaneClick: clearSelection, onRepositoryAdd: handleAddFeatureToRepo, onRepositoryDelete: handleDeleteRepository, onRepositorySelect: handleAddRepository, emptyState: _jsx(ControlCenterEmptyState, { onRepositorySelect: handleAddRepository }) }), _jsx(FeatureDrawer, { selectedNode: showPrdDrawer || showTechDecisionsDrawer ? null : selectedNode, onClose: clearSelection, onDelete: handleDeleteFeature, isDeleting: isDeleting }), questionnaireData ? (_jsx(PrdQuestionnaireDrawer, { open: showPrdDrawer, onClose: clearSelection, featureName: selectedNode?.name ?? '', featureDescription: selectedNode?.description, featureId: selectedNode?.featureId, repositoryPath: selectedNode?.repositoryPath, branch: selectedNode?.branch, specPath: selectedNode?.specPath, data: questionnaireData, selections: prdSelections, onSelect: handlePrdSelect, onRefine: handlePrdRefine, onApprove: handlePrdApprove, onDelete: handleDeleteFeature, isDeleting: isDeleting, isProcessing: isPrdProcessing || isLoadingQuestionnaire })) : null, techDecisionsData ? (_jsx(TechDecisionsDrawer, { open: showTechDecisionsDrawer, onClose: clearSelection, featureName: selectedNode?.name ?? '', featureId: selectedNode?.featureId, repositoryPath: selectedNode?.repositoryPath, branch: selectedNode?.branch, specPath: selectedNode?.specPath, data: techDecisionsData, onRefine: handleTechDecisionsRefine, onApprove: handleTechDecisionsApprove, onDelete: handleDeleteFeature, isDeleting: isDeleting, isProcessing: isLoadingTechDecisions })) : null, _jsx(FeatureCreateDrawer, { open: isCreateDrawerOpen, onClose: closeCreateDrawer, onSubmit: handleCreateFeatureSubmit, repositoryPath: pendingRepositoryPath, workflowDefaults: workflowDefaults })] }));
|
|
215
|
+
return (_jsxs(_Fragment, { children: [_jsx(NotificationPermissionBanner, {}), _jsx(FeaturesCanvas, { nodes: nodes, edges: edges, onNodesChange: onNodesChange, onConnect: handleConnect, onAddFeature: handleAddFeature, onNodeAction: handleAddFeatureToFeature, onNodeClick: handleNodeClick, onPaneClick: clearSelection, onRepositoryAdd: handleAddFeatureToRepo, onRepositoryDelete: handleDeleteRepository, onRepositorySelect: handleAddRepository, emptyState: _jsx(ControlCenterEmptyState, { onRepositorySelect: handleAddRepository }) }), _jsx(FeatureDrawer, { selectedNode: showPrdDrawer || showTechDecisionsDrawer || showMergeReviewDrawer ? null : selectedNode, onClose: clearSelection, onDelete: handleDeleteFeature, isDeleting: isDeleting }), questionnaireData ? (_jsx(PrdQuestionnaireDrawer, { open: showPrdDrawer, onClose: clearSelection, featureName: selectedNode?.name ?? '', featureDescription: selectedNode?.description, featureId: selectedNode?.featureId, repositoryPath: selectedNode?.repositoryPath, branch: selectedNode?.branch, specPath: selectedNode?.specPath, data: questionnaireData, selections: prdSelections, onSelect: handlePrdSelect, onRefine: handlePrdRefine, onApprove: handlePrdApprove, onDelete: handleDeleteFeature, isDeleting: isDeleting, isProcessing: isPrdProcessing || isLoadingQuestionnaire })) : null, techDecisionsData ? (_jsx(TechDecisionsDrawer, { open: showTechDecisionsDrawer, onClose: clearSelection, featureName: selectedNode?.name ?? '', featureId: selectedNode?.featureId, repositoryPath: selectedNode?.repositoryPath, branch: selectedNode?.branch, specPath: selectedNode?.specPath, data: techDecisionsData, onRefine: handleTechDecisionsRefine, onApprove: handleTechDecisionsApprove, onDelete: handleDeleteFeature, isDeleting: isDeleting, isProcessing: isLoadingTechDecisions })) : null, mergeReviewData ? (_jsx(MergeReviewDrawer, { open: showMergeReviewDrawer, onClose: clearSelection, featureName: selectedNode?.name ?? '', featureId: selectedNode?.featureId, repositoryPath: selectedNode?.repositoryPath, branch: selectedNode?.branch, specPath: selectedNode?.specPath, data: mergeReviewData, onApprove: handleMergeApprove, onRefine: handleMergeRefine, onDelete: handleDeleteFeature, isDeleting: isDeleting, isProcessing: isLoadingMergeReview })) : null, _jsx(FeatureCreateDrawer, { open: isCreateDrawerOpen, onClose: closeCreateDrawer, onSubmit: handleCreateFeatureSubmit, repositoryPath: pendingRepositoryPath, workflowDefaults: workflowDefaults })] }));
|
|
162
216
|
}
|
package/dist/src/presentation/web/components/features/control-center/control-center.stories.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"control-center.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/features/control-center/control-center.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAQjD,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,aAAa,CAgBpC,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,IAAI,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"control-center.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/features/control-center/control-center.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAQjD,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,aAAa,CAgBpC,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,IAAI,CAAC,CAAC;AAiFnC,eAAO,MAAM,KAAK,EAAE,KAKnB,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,KAQ1B,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,KAKzB,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,KAS7B,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,WAAW,EAAE,KAYzB,CAAC;AAwIF;;;;;;GAMG;AACH,eAAO,MAAM,WAAW,EAAE,KAKzB,CAAC"}
|
package/dist/src/presentation/web/components/features/control-center/control-center.stories.js
CHANGED
|
@@ -60,6 +60,21 @@ const featureNodes = [
|
|
|
60
60
|
branch: 'feat/api-gateway',
|
|
61
61
|
},
|
|
62
62
|
},
|
|
63
|
+
{
|
|
64
|
+
id: 'feat-4',
|
|
65
|
+
type: 'featureNode',
|
|
66
|
+
position: { x: 800, y: 345 },
|
|
67
|
+
data: {
|
|
68
|
+
name: 'Merge Review',
|
|
69
|
+
description: 'PR ready for merge approval',
|
|
70
|
+
featureId: '#f4',
|
|
71
|
+
lifecycle: 'review',
|
|
72
|
+
state: 'action-required',
|
|
73
|
+
progress: 90,
|
|
74
|
+
repositoryPath: '/home/user/my-repo',
|
|
75
|
+
branch: 'feat/merge-review',
|
|
76
|
+
},
|
|
77
|
+
},
|
|
63
78
|
];
|
|
64
79
|
const repoNode = {
|
|
65
80
|
id: 'repo-1',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-control-center-state.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/features/control-center/use-control-center-state.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAClE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACxE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACtF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAC5E,OAAO,EAAmB,KAAK,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAOhF,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,YAAY,EAAE,eAAe,GAAG,IAAI,CAAC;IACrC,kBAAkB,EAAE,OAAO,CAAC;IAC5B,qBAAqB,EAAE,MAAM,CAAC;IAC9B,aAAa,EAAE,CAAC,OAAO,EAAE,UAAU,CAAC,cAAc,CAAC,EAAE,KAAK,IAAI,CAAC;IAC/D,aAAa,EAAE,CAAC,UAAU,EAAE,UAAU,KAAK,IAAI,CAAC;IAChD,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,eAAe,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,UAAU,EAAE,IAAI,EAAE,cAAc,KAAK,IAAI,CAAC;IACzE,gBAAgB,EAAE,MAAM,IAAI,CAAC;IAC7B,sBAAsB,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IACrD,yBAAyB,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3D,mBAAmB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,YAAY,EAAE,CAAC,SAAS,EAAE,eAAe,KAAK,IAAI,CAAC;IACnD,yBAAyB,EAAE,CAAC,IAAI,EAAE,oBAAoB,KAAK,IAAI,CAAC;IAChE,iBAAiB,EAAE,MAAM,IAAI,CAAC;IAC9B,mBAAmB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1D,sBAAsB,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAChE,UAAU,EAAE,OAAO,CAAC;IACpB,iBAAiB,EAAE,CACjB,YAAY,EAAE,MAAM,GAAG,IAAI,EAC3B,YAAY,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,KACpC,MAAM,CAAC;CACb;AAID,wBAAgB,qBAAqB,CACnC,YAAY,EAAE,cAAc,EAAE,EAC9B,YAAY,EAAE,IAAI,EAAE,GACnB,kBAAkB,
|
|
1
|
+
{"version":3,"file":"use-control-center-state.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/features/control-center/use-control-center-state.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAClE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACxE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACtF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAC5E,OAAO,EAAmB,KAAK,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAOhF,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,YAAY,EAAE,eAAe,GAAG,IAAI,CAAC;IACrC,kBAAkB,EAAE,OAAO,CAAC;IAC5B,qBAAqB,EAAE,MAAM,CAAC;IAC9B,aAAa,EAAE,CAAC,OAAO,EAAE,UAAU,CAAC,cAAc,CAAC,EAAE,KAAK,IAAI,CAAC;IAC/D,aAAa,EAAE,CAAC,UAAU,EAAE,UAAU,KAAK,IAAI,CAAC;IAChD,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,eAAe,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,UAAU,EAAE,IAAI,EAAE,cAAc,KAAK,IAAI,CAAC;IACzE,gBAAgB,EAAE,MAAM,IAAI,CAAC;IAC7B,sBAAsB,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IACrD,yBAAyB,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3D,mBAAmB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,YAAY,EAAE,CAAC,SAAS,EAAE,eAAe,KAAK,IAAI,CAAC;IACnD,yBAAyB,EAAE,CAAC,IAAI,EAAE,oBAAoB,KAAK,IAAI,CAAC;IAChE,iBAAiB,EAAE,MAAM,IAAI,CAAC;IAC9B,mBAAmB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1D,sBAAsB,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAChE,UAAU,EAAE,OAAO,CAAC;IACpB,iBAAiB,EAAE,CACjB,YAAY,EAAE,MAAM,GAAG,IAAI,EAC3B,YAAY,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,KACpC,MAAM,CAAC;CACb;AAID,wBAAgB,qBAAqB,CACnC,YAAY,EAAE,cAAc,EAAE,EAC9B,YAAY,EAAE,IAAI,EAAE,GACnB,kBAAkB,CAsgBpB"}
|
package/dist/src/presentation/web/components/features/control-center/use-control-center-state.js
CHANGED
|
@@ -273,8 +273,17 @@ export function useControlCenterState(initialNodes, initialEdges) {
|
|
|
273
273
|
return;
|
|
274
274
|
}
|
|
275
275
|
setSelectedNode(null);
|
|
276
|
-
setNodes((
|
|
277
|
-
|
|
276
|
+
setNodes((currentNodes) => {
|
|
277
|
+
const remainingNodes = currentNodes.filter((n) => n.id !== featureId);
|
|
278
|
+
const remainingEdges = edges.filter((e) => e.source !== featureId && e.target !== featureId);
|
|
279
|
+
const result = layoutWithDagre(remainingNodes, remainingEdges, {
|
|
280
|
+
direction: 'LR',
|
|
281
|
+
ranksep: 200,
|
|
282
|
+
nodesep: 60,
|
|
283
|
+
});
|
|
284
|
+
setEdges(result.edges);
|
|
285
|
+
return result.nodes;
|
|
286
|
+
});
|
|
278
287
|
toast.success('Feature deleted successfully');
|
|
279
288
|
router.refresh();
|
|
280
289
|
}
|
|
@@ -284,7 +293,7 @@ export function useControlCenterState(initialNodes, initialEdges) {
|
|
|
284
293
|
finally {
|
|
285
294
|
setIsDeleting(false);
|
|
286
295
|
}
|
|
287
|
-
}, [router]);
|
|
296
|
+
}, [router, edges]);
|
|
288
297
|
const handleDeleteRepository = useCallback(async (repositoryId) => {
|
|
289
298
|
const repoNodeId = `repo-${repositoryId}`;
|
|
290
299
|
// Optimistic: remove node and its edges immediately
|
|
@@ -332,27 +341,31 @@ export function useControlCenterState(initialNodes, initialEdges) {
|
|
|
332
341
|
.split(/[\\/]/)
|
|
333
342
|
.pop() ?? path;
|
|
334
343
|
// Optimistic UI: add node immediately
|
|
344
|
+
let savedAddRepoY = 0;
|
|
335
345
|
setNodes((currentNodes) => {
|
|
336
346
|
const repoNodes = currentNodes.filter((n) => n.type === 'repositoryNode');
|
|
337
347
|
const addRepoNode = currentNodes.find((n) => n.type === 'addRepositoryNode');
|
|
338
|
-
//
|
|
348
|
+
// Save addRepoNode's original Y for rollback on error
|
|
349
|
+
if (addRepoNode)
|
|
350
|
+
savedAddRepoY = addRepoNode.position.y;
|
|
351
|
+
// Place in the repo column, at the addRepoNode's current position
|
|
339
352
|
const repoX = repoNodes[0]?.position.x ?? addRepoNode?.position.x ?? 50;
|
|
340
353
|
const repoHeight = 50; // repositoryNode height
|
|
341
354
|
const gap = 15; // match dagre nodesep
|
|
342
|
-
const
|
|
343
|
-
|
|
344
|
-
: addRepoNode
|
|
345
|
-
|
|
346
|
-
: 0;
|
|
347
|
-
const position = { x: repoX, y: lastRepoBottomY + gap };
|
|
355
|
+
const position = {
|
|
356
|
+
x: repoX,
|
|
357
|
+
y: addRepoNode ? addRepoNode.position.y : 0,
|
|
358
|
+
};
|
|
348
359
|
const newNode = {
|
|
349
360
|
id: tempId,
|
|
350
361
|
type: 'repositoryNode',
|
|
351
362
|
position,
|
|
352
363
|
data: { name: repoName, repositoryPath: path, id: tempId },
|
|
353
364
|
};
|
|
354
|
-
//
|
|
355
|
-
const addRepoY =
|
|
365
|
+
// Shift addRepo button down by exactly one slot
|
|
366
|
+
const addRepoY = addRepoNode
|
|
367
|
+
? addRepoNode.position.y + repoHeight + gap
|
|
368
|
+
: position.y + repoHeight + gap;
|
|
356
369
|
return currentNodes
|
|
357
370
|
.map((n) => n.type === 'addRepositoryNode' ? { ...n, position: { ...n.position, y: addRepoY } } : n)
|
|
358
371
|
.concat(newNode);
|
|
@@ -361,8 +374,12 @@ export function useControlCenterState(initialNodes, initialEdges) {
|
|
|
361
374
|
addRepository({ path, name: repoName })
|
|
362
375
|
.then((result) => {
|
|
363
376
|
if (result.error) {
|
|
364
|
-
// Rollback optimistic node
|
|
365
|
-
setNodes((prev) => prev
|
|
377
|
+
// Rollback optimistic node and restore addRepoNode position
|
|
378
|
+
setNodes((prev) => prev
|
|
379
|
+
.filter((n) => n.id !== tempId)
|
|
380
|
+
.map((n) => n.type === 'addRepositoryNode'
|
|
381
|
+
? { ...n, position: { ...n.position, y: savedAddRepoY } }
|
|
382
|
+
: n));
|
|
366
383
|
toast.error(result.error);
|
|
367
384
|
return;
|
|
368
385
|
}
|
|
@@ -385,7 +402,12 @@ export function useControlCenterState(initialNodes, initialEdges) {
|
|
|
385
402
|
router.refresh();
|
|
386
403
|
})
|
|
387
404
|
.catch(() => {
|
|
388
|
-
|
|
405
|
+
// Rollback optimistic node and restore addRepoNode position
|
|
406
|
+
setNodes((prev) => prev
|
|
407
|
+
.filter((n) => n.id !== tempId)
|
|
408
|
+
.map((n) => n.type === 'addRepositoryNode'
|
|
409
|
+
? { ...n, position: { ...n.position, y: savedAddRepoY } }
|
|
410
|
+
: n));
|
|
389
411
|
toast.error('Failed to add repository');
|
|
390
412
|
});
|
|
391
413
|
}, [router]);
|