@shepai/cli 1.47.0 → 1.49.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 +8 -0
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-graph.js +1 -1
- 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 +66 -30
- 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/approve-feature.d.ts +2 -1
- package/dist/src/presentation/web/app/actions/approve-feature.d.ts.map +1 -1
- package/dist/src/presentation/web/app/actions/approve-feature.js +2 -2
- 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/actions/reject-feature.d.ts +7 -0
- package/dist/src/presentation/web/app/actions/reject-feature.d.ts.map +1 -0
- package/dist/src/presentation/web/app/actions/reject-feature.js +34 -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/drawer-action-bar/drawer-action-bar-config.d.ts +24 -0
- package/dist/src/presentation/web/components/common/drawer-action-bar/drawer-action-bar-config.d.ts.map +1 -0
- package/dist/src/presentation/web/components/common/drawer-action-bar/drawer-action-bar-config.js +1 -0
- package/dist/src/presentation/web/components/common/drawer-action-bar/drawer-action-bar.d.ts +3 -0
- package/dist/src/presentation/web/components/common/drawer-action-bar/drawer-action-bar.d.ts.map +1 -0
- package/dist/src/presentation/web/components/common/drawer-action-bar/drawer-action-bar.js +12 -0
- package/dist/src/presentation/web/components/common/drawer-action-bar/index.d.ts +3 -0
- package/dist/src/presentation/web/components/common/drawer-action-bar/index.d.ts.map +1 -0
- package/dist/src/presentation/web/components/common/drawer-action-bar/index.js +1 -0
- package/dist/src/presentation/web/components/common/drawer-revision-input/drawer-revision-input-config.d.ts +11 -0
- package/dist/src/presentation/web/components/common/drawer-revision-input/drawer-revision-input-config.d.ts.map +1 -0
- package/dist/src/presentation/web/components/common/drawer-revision-input/drawer-revision-input-config.js +1 -0
- package/dist/src/presentation/web/components/common/drawer-revision-input/drawer-revision-input.d.ts +3 -0
- package/dist/src/presentation/web/components/common/drawer-revision-input/drawer-revision-input.d.ts.map +1 -0
- package/dist/src/presentation/web/components/common/drawer-revision-input/drawer-revision-input.js +18 -0
- package/dist/src/presentation/web/components/common/drawer-revision-input/index.d.ts +3 -0
- package/dist/src/presentation/web/components/common/drawer-revision-input/index.d.ts.map +1 -0
- package/dist/src/presentation/web/components/common/drawer-revision-input/index.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 +77 -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 +25 -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/common/prd-questionnaire/prd-questionnaire-config.d.ts +4 -2
- package/dist/src/presentation/web/components/common/prd-questionnaire/prd-questionnaire-config.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/prd-questionnaire/prd-questionnaire.d.ts +1 -1
- package/dist/src/presentation/web/components/common/prd-questionnaire/prd-questionnaire.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/prd-questionnaire/prd-questionnaire.js +6 -15
- package/dist/src/presentation/web/components/common/prd-questionnaire/prd-questionnaire.stories.d.ts +4 -0
- package/dist/src/presentation/web/components/common/prd-questionnaire/prd-questionnaire.stories.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/prd-questionnaire/prd-questionnaire.stories.js +24 -3
- package/dist/src/presentation/web/components/common/reject-feedback-dialog/index.d.ts +3 -0
- package/dist/src/presentation/web/components/common/reject-feedback-dialog/index.d.ts.map +1 -0
- package/dist/src/presentation/web/components/common/reject-feedback-dialog/index.js +1 -0
- package/dist/src/presentation/web/components/common/reject-feedback-dialog/reject-feedback-dialog-config.d.ts +9 -0
- package/dist/src/presentation/web/components/common/reject-feedback-dialog/reject-feedback-dialog-config.d.ts.map +1 -0
- package/dist/src/presentation/web/components/common/reject-feedback-dialog/reject-feedback-dialog-config.js +1 -0
- package/dist/src/presentation/web/components/common/reject-feedback-dialog/reject-feedback-dialog.d.ts +3 -0
- package/dist/src/presentation/web/components/common/reject-feedback-dialog/reject-feedback-dialog.d.ts.map +1 -0
- package/dist/src/presentation/web/components/common/reject-feedback-dialog/reject-feedback-dialog.js +19 -0
- package/dist/src/presentation/web/components/common/reject-feedback-dialog/reject-feedback-dialog.stories.d.ts +14 -0
- package/dist/src/presentation/web/components/common/reject-feedback-dialog/reject-feedback-dialog.stories.d.ts.map +1 -0
- package/dist/src/presentation/web/components/common/reject-feedback-dialog/reject-feedback-dialog.stories.js +46 -0
- package/dist/src/presentation/web/components/common/tech-decisions-review/tech-decisions-review-config.d.ts +4 -2
- package/dist/src/presentation/web/components/common/tech-decisions-review/tech-decisions-review-config.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/tech-decisions-review/tech-decisions-review.d.ts +1 -1
- package/dist/src/presentation/web/components/common/tech-decisions-review/tech-decisions-review.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/tech-decisions-review/tech-decisions-review.js +4 -14
- package/dist/src/presentation/web/components/common/tech-decisions-review/tech-decisions-review.stories.d.ts +4 -0
- package/dist/src/presentation/web/components/common/tech-decisions-review/tech-decisions-review.stories.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/tech-decisions-review/tech-decisions-review.stories.js +24 -6
- 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 +88 -19
- 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 +54 -24
- package/web/.next/server/app/page.js +2 -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]__249c74f6._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__2d1a8e37._.js +9 -0
- package/web/.next/server/chunks/ssr/[root-of-the-server]__2d1a8e37._.js.map +1 -0
- package/web/.next/server/chunks/ssr/[root-of-the-server]__d8fbe735._.js +3 -0
- package/web/.next/server/chunks/ssr/[root-of-the-server]__d8fbe735._.js.map +1 -0
- 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 +55 -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 +54 -24
- package/web/.next/standalone/src/presentation/web/.next/server/app/page.js +2 -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]__249c74f6._.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__2d1a8e37._.js +9 -0
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__d8fbe735._.js +3 -0
- 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 +55 -25
- package/web/.next/standalone/src/presentation/web/app/actions/approve-feature.ts +4 -2
- package/web/.next/standalone/src/presentation/web/app/actions/get-merge-review-data.ts +64 -0
- package/web/.next/standalone/src/presentation/web/app/actions/reject-feature.ts +52 -0
- package/web/.next/standalone/src/presentation/web/app/page.tsx +1 -0
- package/web/.next/standalone/src/presentation/web/components/common/drawer-action-bar/drawer-action-bar-config.ts +24 -0
- package/web/.next/standalone/src/presentation/web/components/common/drawer-action-bar/drawer-action-bar.tsx +64 -0
- package/web/.next/standalone/src/presentation/web/components/common/drawer-action-bar/index.ts +2 -0
- package/web/.next/standalone/src/presentation/web/components/common/drawer-revision-input/drawer-revision-input-config.ts +10 -0
- package/web/.next/standalone/src/presentation/web/components/common/drawer-revision-input/drawer-revision-input.tsx +41 -0
- package/web/.next/standalone/src/presentation/web/components/common/drawer-revision-input/index.ts +2 -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 +83 -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 +223 -0
- package/web/.next/standalone/src/presentation/web/components/common/prd-questionnaire/prd-questionnaire-config.ts +4 -2
- package/web/.next/standalone/src/presentation/web/components/common/prd-questionnaire/prd-questionnaire.stories.tsx +36 -8
- package/web/.next/standalone/src/presentation/web/components/common/prd-questionnaire/prd-questionnaire.tsx +16 -47
- package/web/.next/standalone/src/presentation/web/components/common/reject-feedback-dialog/index.ts +2 -0
- package/web/.next/standalone/src/presentation/web/components/common/reject-feedback-dialog/reject-feedback-dialog-config.ts +8 -0
- package/web/.next/standalone/src/presentation/web/components/common/reject-feedback-dialog/reject-feedback-dialog.stories.tsx +63 -0
- package/web/.next/standalone/src/presentation/web/components/common/reject-feedback-dialog/reject-feedback-dialog.tsx +78 -0
- package/web/.next/standalone/src/presentation/web/components/common/tech-decisions-review/tech-decisions-review-config.ts +4 -2
- package/web/.next/standalone/src/presentation/web/components/common/tech-decisions-review/tech-decisions-review.stories.tsx +27 -6
- package/web/.next/standalone/src/presentation/web/components/common/tech-decisions-review/tech-decisions-review.tsx +14 -42
- package/web/.next/standalone/src/presentation/web/components/features/control-center/control-center-inner.tsx +157 -31
- 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/191ca1529c9868dd.js +10 -0
- package/web/.next/static/chunks/22f30ce91a3c79c1.js +1 -0
- package/web/.next/static/chunks/59b8bd47023e0249.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 → UT60KjU8SOYIjqeqo2WT-}/_buildManifest.js +0 -0
- /package/web/.next/static/{wQ3vPV9I8JeacVNyp4HFg → UT60KjU8SOYIjqeqo2WT-}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/static/{wQ3vPV9I8JeacVNyp4HFg → UT60KjU8SOYIjqeqo2WT-}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { fn } from '@storybook/test';
|
|
2
|
+
import { RejectFeedbackDialog } from './reject-feedback-dialog.js';
|
|
3
|
+
const meta = {
|
|
4
|
+
title: 'Composed/RejectFeedbackDialog',
|
|
5
|
+
component: RejectFeedbackDialog,
|
|
6
|
+
tags: ['autodocs'],
|
|
7
|
+
parameters: {
|
|
8
|
+
layout: 'centered',
|
|
9
|
+
},
|
|
10
|
+
args: {
|
|
11
|
+
open: true,
|
|
12
|
+
onOpenChange: fn().mockName('onOpenChange'),
|
|
13
|
+
onConfirm: fn().mockName('onConfirm'),
|
|
14
|
+
isSubmitting: false,
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
export default meta;
|
|
18
|
+
/** Default — dialog open with empty feedback; confirm button disabled. */
|
|
19
|
+
export const Default = {};
|
|
20
|
+
/** With feedback entered — confirm button enabled. */
|
|
21
|
+
export const WithFeedback = {
|
|
22
|
+
play: async ({ canvasElement }) => {
|
|
23
|
+
// Type feedback into the textarea to show enabled state
|
|
24
|
+
const textarea = canvasElement.ownerDocument.querySelector('textarea[aria-label="Rejection feedback"]');
|
|
25
|
+
if (textarea) {
|
|
26
|
+
// Simulate React-compatible input
|
|
27
|
+
const nativeInputValueSetter = Object.getOwnPropertyDescriptor(window.HTMLTextAreaElement.prototype, 'value')?.set;
|
|
28
|
+
nativeInputValueSetter?.call(textarea, 'The requirements are missing error handling for edge cases. Please add validation for empty inputs.');
|
|
29
|
+
textarea.dispatchEvent(new Event('input', { bubbles: true }));
|
|
30
|
+
textarea.dispatchEvent(new Event('change', { bubbles: true }));
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
/** Submitting state — spinner shown, buttons disabled. */
|
|
35
|
+
export const Submitting = {
|
|
36
|
+
args: {
|
|
37
|
+
isSubmitting: true,
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
/** Custom title and description for tech decisions context. */
|
|
41
|
+
export const CustomTitle = {
|
|
42
|
+
args: {
|
|
43
|
+
title: 'Reject Plan',
|
|
44
|
+
description: 'Provide feedback on the technical plan for the agent to revise. Be specific about which decisions need changes.',
|
|
45
|
+
},
|
|
46
|
+
};
|
|
@@ -9,12 +9,14 @@ export interface TechDecisionsReviewData {
|
|
|
9
9
|
export interface TechDecisionsReviewProps {
|
|
10
10
|
/** Tech decisions data from the research artifact */
|
|
11
11
|
data: TechDecisionsReviewData;
|
|
12
|
-
/** Chat refinement callback — sends user feedback to the agent */
|
|
13
|
-
onRefine: (text: string) => void;
|
|
14
12
|
/** Approve plan callback */
|
|
15
13
|
onApprove: () => void;
|
|
14
|
+
/** Reject plan callback — opens feedback dialog when provided; also used for inline text rejection */
|
|
15
|
+
onReject?: (feedback: string) => void;
|
|
16
16
|
/** Controls disabled state during loading */
|
|
17
17
|
isProcessing?: boolean;
|
|
18
|
+
/** Whether a reject operation is in flight */
|
|
19
|
+
isRejecting?: boolean;
|
|
18
20
|
}
|
|
19
21
|
export interface TechDecisionsDrawerProps extends TechDecisionsReviewProps {
|
|
20
22
|
/** Whether the drawer is open */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tech-decisions-review-config.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/tech-decisions-review/tech-decisions-review-config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sCAAsC,CAAC;AAEzE,YAAY,EAAE,YAAY,EAAE,CAAC;AAE7B,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,YAAY,EAAE,CAAC;IAC1B,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAED,MAAM,WAAW,wBAAwB;IACvC,qDAAqD;IACrD,IAAI,EAAE,uBAAuB,CAAC;IAC9B,
|
|
1
|
+
{"version":3,"file":"tech-decisions-review-config.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/tech-decisions-review/tech-decisions-review-config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sCAAsC,CAAC;AAEzE,YAAY,EAAE,YAAY,EAAE,CAAC;AAE7B,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,YAAY,EAAE,CAAC;IAC1B,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAED,MAAM,WAAW,wBAAwB;IACvC,qDAAqD;IACrD,IAAI,EAAE,uBAAuB,CAAC;IAC9B,4BAA4B;IAC5B,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,sGAAsG;IACtG,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,6CAA6C;IAC7C,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,8CAA8C;IAC9C,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,wBAAyB,SAAQ,wBAAwB;IACxE,iCAAiC;IACjC,IAAI,EAAE,OAAO,CAAC;IACd,wCAAwC;IACxC,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,0CAA0C;IAC1C,WAAW,EAAE,MAAM,CAAC;IACpB,sCAAsC;IACtC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,8CAA8C;IAC9C,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,uCAAuC;IACvC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gDAAgD;IAChD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,yEAAyE;IACzE,QAAQ,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,gDAAgD;IAChD,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB"}
|
package/dist/src/presentation/web/components/common/tech-decisions-review/tech-decisions-review.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { TechDecisionsReviewProps } from './tech-decisions-review-config.js';
|
|
2
|
-
export declare function TechDecisionsReview({ data,
|
|
2
|
+
export declare function TechDecisionsReview({ data, onApprove, onReject, isProcessing, isRejecting, }: TechDecisionsReviewProps): import("react/jsx-runtime").JSX.Element | null;
|
|
3
3
|
//# sourceMappingURL=tech-decisions-review.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tech-decisions-review.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/tech-decisions-review/tech-decisions-review.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"tech-decisions-review.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/tech-decisions-review/tech-decisions-review.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,wBAAwB,EAAgB,MAAM,gCAAgC,CAAC;AAoG7F,wBAAgB,mBAAmB,CAAC,EAClC,IAAI,EACJ,SAAS,EACT,QAAQ,EACR,YAAoB,EACpB,WAAmB,GACpB,EAAE,wBAAwB,kDA6C1B"}
|
package/dist/src/presentation/web/components/common/tech-decisions-review/tech-decisions-review.js
CHANGED
|
@@ -2,10 +2,9 @@
|
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useState } from 'react';
|
|
4
4
|
import Markdown from 'react-markdown';
|
|
5
|
-
import { Check, ChevronRight, GitCompareArrows, Layers
|
|
5
|
+
import { Check, ChevronRight, GitCompareArrows, Layers } from 'lucide-react';
|
|
6
6
|
import { Badge } from '../../ui/badge.js';
|
|
7
|
-
import {
|
|
8
|
-
import { Input } from '../../ui/input.js';
|
|
7
|
+
import { DrawerActionBar } from '../../common/drawer-action-bar/index.js';
|
|
9
8
|
const markdownComponents = {
|
|
10
9
|
p: ({ children }) => (_jsx("p", { className: "text-muted-foreground mb-2 text-xs leading-relaxed last:mb-0", children: children })),
|
|
11
10
|
strong: ({ children }) => _jsx("strong", { className: "text-foreground font-semibold", children: children }),
|
|
@@ -22,18 +21,9 @@ function DecisionCard({ decision, index }) {
|
|
|
22
21
|
return (_jsxs("div", { className: "border-border rounded-lg border", children: [_jsxs("div", { className: "space-y-3 px-4 py-3", children: [_jsxs("div", { className: "flex items-start justify-between gap-3", children: [_jsxs("div", { className: "flex items-start gap-2.5", children: [_jsx("span", { className: "bg-primary text-primary-foreground flex h-6 w-6 shrink-0 items-center justify-center rounded-full text-xs font-bold", children: index + 1 }), _jsxs("div", { className: "min-w-0", children: [_jsx("h3", { className: "text-foreground text-sm leading-tight font-semibold", children: decision.title }), _jsx("p", { className: "text-muted-foreground mt-0.5 text-xs", children: decision.chosen })] })] }), 'decisionName' in decision &&
|
|
23
22
|
decision.decisionName ? (_jsx(Badge, { variant: "secondary", className: "bg-primary/10 text-primary shrink-0", children: decision.decisionName })) : null] }), decision.rationale ? (_jsx(Markdown, { components: markdownComponents, children: decision.rationale })) : null] }), decision.rejected.length > 0 ? (_jsxs("div", { className: "border-border border-t", children: [_jsxs("button", { type: "button", onClick: () => setAlternativesOpen((prev) => !prev), className: "text-muted-foreground hover:bg-muted/50 flex w-full items-center gap-1.5 px-4 py-3 text-xs font-medium transition-colors", children: [_jsx(ChevronRight, { className: `h-3.5 w-3.5 transition-transform ${alternativesOpen ? 'rotate-90' : ''}` }), _jsx(Layers, { className: "h-3.5 w-3.5" }), "Other Options Considered (", decision.rejected.length, ")"] }), alternativesOpen ? (_jsx("div", { className: "space-y-1.5 px-4 pb-3", children: decision.rejected.map((alt) => (_jsx("div", { className: "bg-primary/5 rounded-md px-3 py-2", children: _jsx("span", { className: "text-foreground text-xs", children: alt }) }, alt))) })) : null] })) : null] }));
|
|
24
23
|
}
|
|
25
|
-
export function TechDecisionsReview({ data,
|
|
24
|
+
export function TechDecisionsReview({ data, onApprove, onReject, isProcessing = false, isRejecting = false, }) {
|
|
26
25
|
const { summary, decisions } = data;
|
|
27
|
-
const [chatInput, setChatInput] = useState('');
|
|
28
|
-
function handleSubmit(e) {
|
|
29
|
-
e.preventDefault();
|
|
30
|
-
const text = chatInput.trim();
|
|
31
|
-
if (!text)
|
|
32
|
-
return;
|
|
33
|
-
onRefine(text);
|
|
34
|
-
setChatInput('');
|
|
35
|
-
}
|
|
36
26
|
if (decisions.length === 0)
|
|
37
27
|
return null;
|
|
38
|
-
return (_jsxs("div", { className: "flex h-full flex-col", children: [_jsxs("div", { className: "flex-1 space-y-4 overflow-y-auto p-4", children: [_jsxs("div", { className: "flex items-start gap-3", children: [_jsx("div", { className: "mt-1.5 h-2.5 w-2.5 shrink-0 rounded-full bg-blue-500" }), _jsxs("div", { className: "flex-1", children: [_jsx("h2", { className: "text-foreground text-sm font-bold", children: "Technical Implementation Plan Review" }), summary ? (_jsx("p", { className: "text-muted-foreground mt-1 text-xs leading-relaxed", children: summary })) : null] })] }), _jsxs("div", { className: "flex items-center gap-2 pt-1", children: [_jsx(GitCompareArrows, { className: "text-primary h-4 w-4" }), _jsx("h3", { className: "text-foreground text-sm font-bold", children: "Technical Decisions" })] }), decisions.map((decision, i) => (_jsx(DecisionCard, { decision: decision, index: i }, decision.title)))] }),
|
|
28
|
+
return (_jsxs("div", { className: "flex h-full flex-col", children: [_jsxs("div", { className: "flex-1 space-y-4 overflow-y-auto p-4", children: [_jsxs("div", { className: "flex items-start gap-3", children: [_jsx("div", { className: "mt-1.5 h-2.5 w-2.5 shrink-0 rounded-full bg-blue-500" }), _jsxs("div", { className: "flex-1", children: [_jsx("h2", { className: "text-foreground text-sm font-bold", children: "Technical Implementation Plan Review" }), summary ? (_jsx("p", { className: "text-muted-foreground mt-1 text-xs leading-relaxed", children: summary })) : null] })] }), _jsxs("div", { className: "flex items-center gap-2 pt-1", children: [_jsx(GitCompareArrows, { className: "text-primary h-4 w-4" }), _jsx("h3", { className: "text-foreground text-sm font-bold", children: "Technical Decisions" })] }), decisions.map((decision, i) => (_jsx(DecisionCard, { decision: decision, index: i }, decision.title)))] }), _jsx(DrawerActionBar, { onReject: onReject, onApprove: onApprove, approveLabel: "Approve Plan", approveIcon: _jsx(Check, { className: "mr-1.5 h-4 w-4" }), revisionPlaceholder: "Ask AI to revise the plan...", rejectDialogTitle: "Reject Plan", isProcessing: isProcessing, isRejecting: isRejecting })] }));
|
|
39
29
|
}
|
|
@@ -19,4 +19,8 @@ export declare const InDrawer: DrawerStory;
|
|
|
19
19
|
export declare const WithDeleteButton: DrawerStory;
|
|
20
20
|
/** Drawer with delete in progress (button disabled). */
|
|
21
21
|
export declare const DeletingState: DrawerStory;
|
|
22
|
+
/** With reject button visible next to approve. */
|
|
23
|
+
export declare const WithRejectButton: Story;
|
|
24
|
+
/** Rejecting state — reject button disabled while reject action is in flight. */
|
|
25
|
+
export declare const RejectingState: Story;
|
|
22
26
|
//# sourceMappingURL=tech-decisions-review.stories.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tech-decisions-review.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/tech-decisions-review/tech-decisions-review.stories.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AA0C9D,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,mBAAmB,CAc1C,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAElD,oDAAoD;AACpD,eAAO,MAAM,OAAO,EAAE,KAMrB,CAAC;AAEF,kDAAkD;AAClD,eAAO,MAAM,UAAU,EAAE,KAMxB,CAAC;AAEF,uBAAuB;AACvB,eAAO,MAAM,cAAc,EAAE,KAM5B,CAAC;AAEF,8BAA8B;AAC9B,eAAO,MAAM,cAAc,EAAE,KAM5B,CAAC;AAIF,KAAK,WAAW,GAAG,QAAQ,CAAC,OAAO,mBAAmB,CAAC,CAAC;AA8BxD,uCAAuC;AACvC,eAAO,MAAM,QAAQ,EAAE,WAWtB,CAAC;AAEF,yCAAyC;AACzC,eAAO,MAAM,gBAAgB,EAAE,WAY9B,CAAC;AAEF,wDAAwD;AACxD,eAAO,MAAM,aAAa,EAAE,WAa3B,CAAC"}
|
|
1
|
+
{"version":3,"file":"tech-decisions-review.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/tech-decisions-review/tech-decisions-review.stories.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AA0C9D,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,mBAAmB,CAc1C,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAElD,oDAAoD;AACpD,eAAO,MAAM,OAAO,EAAE,KAMrB,CAAC;AAEF,kDAAkD;AAClD,eAAO,MAAM,UAAU,EAAE,KAMxB,CAAC;AAEF,uBAAuB;AACvB,eAAO,MAAM,cAAc,EAAE,KAM5B,CAAC;AAEF,8BAA8B;AAC9B,eAAO,MAAM,cAAc,EAAE,KAM5B,CAAC;AAIF,KAAK,WAAW,GAAG,QAAQ,CAAC,OAAO,mBAAmB,CAAC,CAAC;AA8BxD,uCAAuC;AACvC,eAAO,MAAM,QAAQ,EAAE,WAWtB,CAAC;AAEF,yCAAyC;AACzC,eAAO,MAAM,gBAAgB,EAAE,WAY9B,CAAC;AAEF,wDAAwD;AACxD,eAAO,MAAM,aAAa,EAAE,WAa3B,CAAC;AAIF,kDAAkD;AAClD,eAAO,MAAM,gBAAgB,EAAE,KAM9B,CAAC;AAEF,iFAAiF;AACjF,eAAO,MAAM,cAAc,EAAE,KAO5B,CAAC"}
|
|
@@ -51,7 +51,7 @@ export default meta;
|
|
|
51
51
|
export const Default = {
|
|
52
52
|
args: {
|
|
53
53
|
data: mockData,
|
|
54
|
-
|
|
54
|
+
onReject: fn().mockName('onReject'),
|
|
55
55
|
onApprove: fn().mockName('onApprove'),
|
|
56
56
|
},
|
|
57
57
|
};
|
|
@@ -67,7 +67,7 @@ export const Processing = {
|
|
|
67
67
|
export const SingleDecision = {
|
|
68
68
|
args: {
|
|
69
69
|
data: { ...mockData, decisions: [mockData.decisions[0]] },
|
|
70
|
-
|
|
70
|
+
onReject: fn().mockName('onReject'),
|
|
71
71
|
onApprove: fn().mockName('onApprove'),
|
|
72
72
|
},
|
|
73
73
|
};
|
|
@@ -75,7 +75,7 @@ export const SingleDecision = {
|
|
|
75
75
|
export const NoTechnologies = {
|
|
76
76
|
args: {
|
|
77
77
|
data: { ...mockData, technologies: [] },
|
|
78
|
-
|
|
78
|
+
onReject: fn().mockName('onReject'),
|
|
79
79
|
onApprove: fn().mockName('onApprove'),
|
|
80
80
|
},
|
|
81
81
|
};
|
|
@@ -94,15 +94,33 @@ function DrawerTemplate(props) {
|
|
|
94
94
|
/** Drawer with tech decisions list. */
|
|
95
95
|
export const InDrawer = {
|
|
96
96
|
...drawerMeta,
|
|
97
|
-
render: () => (_jsx(DrawerTemplate, { featureName: "Agent Executor Abstraction", featureId: "FEAT-099", data: mockData,
|
|
97
|
+
render: () => (_jsx(DrawerTemplate, { featureName: "Agent Executor Abstraction", featureId: "FEAT-099", data: mockData, onApprove: fn().mockName('onApprove'), onReject: fn().mockName('onReject') })),
|
|
98
98
|
};
|
|
99
99
|
/** Drawer with delete button visible. */
|
|
100
100
|
export const WithDeleteButton = {
|
|
101
101
|
...drawerMeta,
|
|
102
|
-
render: () => (_jsx(DrawerTemplate, { featureName: "Agent Executor Abstraction", featureId: "FEAT-099", data: mockData,
|
|
102
|
+
render: () => (_jsx(DrawerTemplate, { featureName: "Agent Executor Abstraction", featureId: "FEAT-099", data: mockData, onApprove: fn().mockName('onApprove'), onReject: fn().mockName('onReject'), onDelete: fn().mockName('onDelete') })),
|
|
103
103
|
};
|
|
104
104
|
/** Drawer with delete in progress (button disabled). */
|
|
105
105
|
export const DeletingState = {
|
|
106
106
|
...drawerMeta,
|
|
107
|
-
render: () => (_jsx(DrawerTemplate, { featureName: "Agent Executor Abstraction", featureId: "FEAT-099", data: mockData,
|
|
107
|
+
render: () => (_jsx(DrawerTemplate, { featureName: "Agent Executor Abstraction", featureId: "FEAT-099", data: mockData, onApprove: fn().mockName('onApprove'), onReject: fn().mockName('onReject'), onDelete: fn().mockName('onDelete'), isDeleting: true })),
|
|
108
|
+
};
|
|
109
|
+
/* ─── Reject Variants ─── */
|
|
110
|
+
/** With reject button visible next to approve. */
|
|
111
|
+
export const WithRejectButton = {
|
|
112
|
+
args: {
|
|
113
|
+
data: mockData,
|
|
114
|
+
onApprove: fn().mockName('onApprove'),
|
|
115
|
+
onReject: fn().mockName('onReject'),
|
|
116
|
+
},
|
|
117
|
+
};
|
|
118
|
+
/** Rejecting state — reject button disabled while reject action is in flight. */
|
|
119
|
+
export const RejectingState = {
|
|
120
|
+
args: {
|
|
121
|
+
data: mockData,
|
|
122
|
+
onApprove: fn().mockName('onApprove'),
|
|
123
|
+
onReject: fn().mockName('onReject'),
|
|
124
|
+
isRejecting: true,
|
|
125
|
+
},
|
|
108
126
|
};
|
package/dist/src/presentation/web/components/features/control-center/control-center-inner.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"control-center-inner.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/features/control-center/control-center-inner.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"control-center-inner.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/features/control-center/control-center-inner.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAgB1C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAU5E,UAAU,uBAAuB;IAC/B,YAAY,EAAE,cAAc,EAAE,CAAC;IAC/B,YAAY,EAAE,IAAI,EAAE,CAAC;CACtB;AAED,wBAAgB,kBAAkB,CAAC,EAAE,YAAY,EAAE,YAAY,EAAE,EAAE,uBAAuB,2CAiYzF"}
|
package/dist/src/presentation/web/components/features/control-center/control-center-inner.js
CHANGED
|
@@ -3,13 +3,16 @@ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-run
|
|
|
3
3
|
import { useCallback, useEffect, useState } from 'react';
|
|
4
4
|
import { toast } from 'sonner';
|
|
5
5
|
import { approveFeature } from '../../../app/actions/approve-feature.js';
|
|
6
|
+
import { rejectFeature } from '../../../app/actions/reject-feature.js';
|
|
6
7
|
import { getFeatureArtifact } from '../../../app/actions/get-feature-artifact.js';
|
|
7
8
|
import { getResearchArtifact } from '../../../app/actions/get-research-artifact.js';
|
|
8
9
|
import { getWorkflowDefaults } from '../../../app/actions/get-workflow-defaults.js';
|
|
10
|
+
import { getMergeReviewData } from '../../../app/actions/get-merge-review-data.js';
|
|
9
11
|
import { FeaturesCanvas } from '../../features/features-canvas/index.js';
|
|
10
12
|
import { FeatureDrawer, FeatureCreateDrawer } from '../../common/index.js';
|
|
11
13
|
import { PrdQuestionnaireDrawer } from '../../common/prd-questionnaire/index.js';
|
|
12
14
|
import { TechDecisionsDrawer } from '../../common/tech-decisions-review/index.js';
|
|
15
|
+
import { MergeReviewDrawer } from '../../common/merge-review/index.js';
|
|
13
16
|
import { NotificationPermissionBanner } from '../../common/notification-permission-banner/index.js';
|
|
14
17
|
import { ControlCenterEmptyState } from './control-center-empty-state.js';
|
|
15
18
|
import { useControlCenterState } from './use-control-center-state.js';
|
|
@@ -26,29 +29,42 @@ export function ControlCenterInner({ initialNodes, initialEdges }) {
|
|
|
26
29
|
}, []);
|
|
27
30
|
// PRD questionnaire drawer state
|
|
28
31
|
const [prdSelections, setPrdSelections] = useState({});
|
|
29
|
-
const [isPrdProcessing, setIsPrdProcessing] = useState(false);
|
|
30
32
|
const [questionnaireData, setQuestionnaireData] = useState(null);
|
|
31
33
|
const [isLoadingQuestionnaire, setIsLoadingQuestionnaire] = useState(false);
|
|
34
|
+
// Reject state (shared by both drawers)
|
|
35
|
+
const [isRejecting, setIsRejecting] = useState(false);
|
|
32
36
|
// Tech decisions drawer state
|
|
33
37
|
const [techDecisionsData, setTechDecisionsData] = useState(null);
|
|
34
38
|
const [isLoadingTechDecisions, setIsLoadingTechDecisions] = useState(false);
|
|
39
|
+
// Merge review drawer state
|
|
40
|
+
const [mergeReviewData, setMergeReviewData] = useState(null);
|
|
41
|
+
const [isLoadingMergeReview, setIsLoadingMergeReview] = useState(false);
|
|
35
42
|
const showPrdDrawer = selectedNode?.lifecycle === 'requirements' && selectedNode?.state === 'action-required';
|
|
36
43
|
const showTechDecisionsDrawer = selectedNode?.lifecycle === 'implementation' && selectedNode?.state === 'action-required';
|
|
44
|
+
const showMergeReviewDrawer = selectedNode?.lifecycle === 'review' && selectedNode?.state === 'action-required';
|
|
37
45
|
const handlePrdSelect = useCallback((questionId, optionId) => {
|
|
38
46
|
setPrdSelections((prev) => ({ ...prev, [questionId]: optionId }));
|
|
39
47
|
}, []);
|
|
40
|
-
const handlePrdRefine = useCallback(async (_text) => {
|
|
41
|
-
setIsPrdProcessing(true);
|
|
42
|
-
// TODO: Call API to refine requirements
|
|
43
|
-
// For now simulate a delay
|
|
44
|
-
await new Promise((resolve) => setTimeout(resolve, 1500));
|
|
45
|
-
setIsPrdProcessing(false);
|
|
46
|
-
}, []);
|
|
47
48
|
const handlePrdApprove = useCallback(async (_actionId) => {
|
|
48
49
|
const featureId = selectedNode?.featureId;
|
|
49
50
|
if (!featureId)
|
|
50
51
|
return;
|
|
51
|
-
|
|
52
|
+
let payload;
|
|
53
|
+
if (questionnaireData) {
|
|
54
|
+
const changedSelections = [];
|
|
55
|
+
for (const [questionId, optionId] of Object.entries(prdSelections)) {
|
|
56
|
+
const question = questionnaireData.questions.find((q) => q.id === questionId);
|
|
57
|
+
const option = question?.options.find((o) => o.id === optionId);
|
|
58
|
+
if (question && option) {
|
|
59
|
+
changedSelections.push({
|
|
60
|
+
questionId: question.question,
|
|
61
|
+
selectedOption: option.label,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
payload = { approved: true, changedSelections };
|
|
66
|
+
}
|
|
67
|
+
const result = await approveFeature(featureId, payload);
|
|
52
68
|
if (!result.approved) {
|
|
53
69
|
toast.error(result.error ?? 'Failed to approve requirements');
|
|
54
70
|
return;
|
|
@@ -56,25 +72,48 @@ export function ControlCenterInner({ initialNodes, initialEdges }) {
|
|
|
56
72
|
toast.success('Requirements approved — agent resuming');
|
|
57
73
|
clearSelection();
|
|
58
74
|
setPrdSelections({});
|
|
75
|
+
}, [selectedNode?.featureId, clearSelection, questionnaireData, prdSelections]);
|
|
76
|
+
// Shared reject handler — all drawers use the same rejectFeature flow
|
|
77
|
+
const handleReject = useCallback(async (feedback, label, onDone) => {
|
|
78
|
+
const featureId = selectedNode?.featureId;
|
|
79
|
+
if (!featureId)
|
|
80
|
+
return;
|
|
81
|
+
setIsRejecting(true);
|
|
82
|
+
try {
|
|
83
|
+
const result = await rejectFeature(featureId, feedback);
|
|
84
|
+
if (!result.rejected) {
|
|
85
|
+
toast.error(result.error ?? `Failed to reject ${label.toLowerCase()}`);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
toast.success(`${label} rejected — agent re-iterating (iteration ${result.iteration})`);
|
|
89
|
+
if (result.iterationWarning) {
|
|
90
|
+
toast.warning(`Iteration ${result.iteration} — consider approving or adjusting feedback to avoid excessive iterations`);
|
|
91
|
+
}
|
|
92
|
+
clearSelection();
|
|
93
|
+
onDone?.();
|
|
94
|
+
}
|
|
95
|
+
finally {
|
|
96
|
+
setIsRejecting(false);
|
|
97
|
+
}
|
|
59
98
|
}, [selectedNode?.featureId, clearSelection]);
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
}, []);
|
|
66
|
-
const handleTechDecisionsApprove = useCallback(async () => {
|
|
99
|
+
const handlePrdReject = useCallback((feedback) => handleReject(feedback, 'Requirements', () => setPrdSelections({})), [handleReject]);
|
|
100
|
+
const handleTechDecisionsReject = useCallback((feedback) => handleReject(feedback, 'Plan'), [handleReject]);
|
|
101
|
+
const handleMergeReject = useCallback((feedback) => handleReject(feedback, 'Merge'), [handleReject]);
|
|
102
|
+
// Shared approve handler — tech decisions and merge use identical approve flows
|
|
103
|
+
const handleSimpleApprove = useCallback(async (label) => {
|
|
67
104
|
const featureId = selectedNode?.featureId;
|
|
68
105
|
if (!featureId)
|
|
69
106
|
return;
|
|
70
107
|
const result = await approveFeature(featureId);
|
|
71
108
|
if (!result.approved) {
|
|
72
|
-
toast.error(result.error ??
|
|
109
|
+
toast.error(result.error ?? `Failed to approve ${label.toLowerCase()}`);
|
|
73
110
|
return;
|
|
74
111
|
}
|
|
75
|
-
toast.success(
|
|
112
|
+
toast.success(`${label} approved — agent resuming`);
|
|
76
113
|
clearSelection();
|
|
77
114
|
}, [selectedNode?.featureId, clearSelection]);
|
|
115
|
+
const handleTechDecisionsApprove = useCallback(() => handleSimpleApprove('Plan'), [handleSimpleApprove]);
|
|
116
|
+
const handleMergeApprove = useCallback(() => handleSimpleApprove('Merge'), [handleSimpleApprove]);
|
|
78
117
|
// Fetch questionnaire data and reset selections when a different feature is selected
|
|
79
118
|
const prdFeatureId = showPrdDrawer ? selectedNode?.featureId : null;
|
|
80
119
|
useEffect(() => {
|
|
@@ -148,6 +187,36 @@ export function ControlCenterInner({ initialNodes, initialEdges }) {
|
|
|
148
187
|
cancelled = true;
|
|
149
188
|
};
|
|
150
189
|
}, [techDecisionsFeatureId]);
|
|
190
|
+
// Fetch merge review data when a feature is in review + action-required
|
|
191
|
+
const mergeFeatureId = showMergeReviewDrawer ? selectedNode?.featureId : null;
|
|
192
|
+
useEffect(() => {
|
|
193
|
+
setMergeReviewData(null);
|
|
194
|
+
if (!mergeFeatureId)
|
|
195
|
+
return;
|
|
196
|
+
let cancelled = false;
|
|
197
|
+
setIsLoadingMergeReview(true);
|
|
198
|
+
getMergeReviewData(mergeFeatureId)
|
|
199
|
+
.then((result) => {
|
|
200
|
+
if (cancelled)
|
|
201
|
+
return;
|
|
202
|
+
if ('error' in result) {
|
|
203
|
+
toast.error(result.error);
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
setMergeReviewData(result);
|
|
207
|
+
})
|
|
208
|
+
.catch(() => {
|
|
209
|
+
if (!cancelled)
|
|
210
|
+
toast.error('Failed to load merge review data');
|
|
211
|
+
})
|
|
212
|
+
.finally(() => {
|
|
213
|
+
if (!cancelled)
|
|
214
|
+
setIsLoadingMergeReview(false);
|
|
215
|
+
});
|
|
216
|
+
return () => {
|
|
217
|
+
cancelled = true;
|
|
218
|
+
};
|
|
219
|
+
}, [mergeFeatureId]);
|
|
151
220
|
const hasRepositories = nodes.some((n) => n.type === 'repositoryNode');
|
|
152
221
|
// Listen for global "open create drawer" events from the sidebar
|
|
153
222
|
useEffect(() => {
|
|
@@ -158,5 +227,5 @@ export function ControlCenterInner({ initialNodes, initialEdges }) {
|
|
|
158
227
|
if (!hasRepositories) {
|
|
159
228
|
return (_jsxs(_Fragment, { children: [_jsx(NotificationPermissionBanner, {}), _jsx(ControlCenterEmptyState, { onRepositorySelect: handleAddRepository }), _jsx(FeatureCreateDrawer, { open: isCreateDrawerOpen, onClose: closeCreateDrawer, onSubmit: handleCreateFeatureSubmit, repositoryPath: pendingRepositoryPath, workflowDefaults: workflowDefaults })] }));
|
|
160
229
|
}
|
|
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,
|
|
230
|
+
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, onApprove: handlePrdApprove, onReject: handlePrdReject, isRejecting: isRejecting, onDelete: handleDeleteFeature, isDeleting: isDeleting, isProcessing: 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, onApprove: handleTechDecisionsApprove, onReject: handleTechDecisionsReject, isRejecting: isRejecting, 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, onReject: handleMergeReject, isRejecting: isRejecting, onDelete: handleDeleteFeature, isDeleting: isDeleting, isProcessing: isLoadingMergeReview })) : null, _jsx(FeatureCreateDrawer, { open: isCreateDrawerOpen, onClose: closeCreateDrawer, onSubmit: handleCreateFeatureSubmit, repositoryPath: pendingRepositoryPath, workflowDefaults: workflowDefaults })] }));
|
|
162
231
|
}
|
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]);
|