@shepai/cli 1.27.0 → 1.29.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/dist/packages/core/src/domain/generated/output.d.ts +4 -0
- package/dist/packages/core/src/domain/generated/output.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/di/populate-use-cases-bridge.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/di/populate-use-cases-bridge.js +2 -0
- package/dist/packages/core/src/infrastructure/di/use-cases-bridge.d.ts +7 -0
- package/dist/packages/core/src/infrastructure/di/use-cases-bridge.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/di/use-cases-bridge.js +17 -1
- package/dist/src/presentation/cli/commands/feat/new.command.d.ts.map +1 -1
- package/dist/src/presentation/cli/commands/feat/new.command.js +7 -6
- package/dist/src/presentation/web/app/api/features/[id]/route.d.ts +11 -0
- package/dist/src/presentation/web/app/api/features/[id]/route.d.ts.map +1 -0
- package/dist/src/presentation/web/app/api/features/[id]/route.js +16 -0
- package/dist/src/presentation/web/app/api/features/create/route.d.ts.map +1 -1
- package/dist/src/presentation/web/app/api/features/create/route.js +28 -2
- package/dist/src/presentation/web/components/common/feature-create-drawer/feature-create-drawer.d.ts +4 -8
- package/dist/src/presentation/web/components/common/feature-create-drawer/feature-create-drawer.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/feature-create-drawer/feature-create-drawer.js +37 -4
- package/dist/src/presentation/web/components/common/feature-create-drawer/feature-create-drawer.stories.d.ts +30 -6
- package/dist/src/presentation/web/components/common/feature-create-drawer/feature-create-drawer.stories.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/feature-create-drawer/feature-create-drawer.stories.js +74 -18
- package/dist/src/presentation/web/components/common/feature-create-drawer/index.d.ts +1 -1
- package/dist/src/presentation/web/components/common/feature-create-drawer/index.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/feature-drawer/feature-drawer.d.ts +3 -1
- package/dist/src/presentation/web/components/common/feature-drawer/feature-drawer.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/feature-drawer/feature-drawer.js +4 -3
- package/dist/src/presentation/web/components/common/feature-drawer/feature-drawer.stories.d.ts +6 -0
- package/dist/src/presentation/web/components/common/feature-drawer/feature-drawer.stories.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/feature-drawer/feature-drawer.stories.js +22 -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 +3 -0
- package/dist/src/presentation/web/components/common/index.d.ts +1 -1
- package/dist/src/presentation/web/components/common/index.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/index.js +1 -1
- 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 +2 -2
- package/dist/src/presentation/web/components/features/control-center/use-control-center-state.d.ts +5 -2
- 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 +31 -12
- package/dist/src/presentation/web/components/ui/alert-dialog.d.ts +19 -0
- package/dist/src/presentation/web/components/ui/alert-dialog.d.ts.map +1 -0
- package/dist/src/presentation/web/components/ui/alert-dialog.js +42 -0
- package/dist/src/presentation/web/components/ui/alert-dialog.stories.d.ts +9 -0
- package/dist/src/presentation/web/components/ui/alert-dialog.stories.d.ts.map +1 -0
- package/dist/src/presentation/web/components/ui/alert-dialog.stories.js +21 -0
- package/dist/src/presentation/web/components/ui/checkbox-group-item.d.ts +11 -0
- package/dist/src/presentation/web/components/ui/checkbox-group-item.d.ts.map +1 -0
- package/dist/src/presentation/web/components/ui/checkbox-group-item.js +8 -0
- package/dist/src/presentation/web/components/ui/checkbox-group-item.stories.d.ts +17 -0
- package/dist/src/presentation/web/components/ui/checkbox-group-item.stories.d.ts.map +1 -0
- package/dist/src/presentation/web/components/ui/checkbox-group-item.stories.js +33 -0
- package/dist/src/presentation/web/components/ui/checkbox-group.d.ts +21 -0
- package/dist/src/presentation/web/components/ui/checkbox-group.d.ts.map +1 -0
- package/dist/src/presentation/web/components/ui/checkbox-group.js +24 -0
- package/dist/src/presentation/web/components/ui/checkbox-group.stories.d.ts +23 -0
- package/dist/src/presentation/web/components/ui/checkbox-group.stories.d.ts.map +1 -0
- package/dist/src/presentation/web/components/ui/checkbox-group.stories.js +61 -0
- package/dist/src/presentation/web/components/ui/checkbox.d.ts +5 -0
- package/dist/src/presentation/web/components/ui/checkbox.d.ts.map +1 -0
- package/dist/src/presentation/web/components/ui/checkbox.js +9 -0
- package/dist/src/presentation/web/components/ui/checkbox.stories.d.ts +10 -0
- package/dist/src/presentation/web/components/ui/checkbox.stories.d.ts.map +1 -0
- package/dist/src/presentation/web/components/ui/checkbox.stories.js +24 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/web/.next/BUILD_ID +1 -1
- package/web/.next/app-path-routes-manifest.json +1 -0
- 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/routes-manifest.json +10 -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/_not-found.html +2 -2
- package/web/.next/server/app/_not-found.rsc +10 -10
- package/web/.next/server/app/_not-found.segments/_full.segment.rsc +10 -10
- package/web/.next/server/app/_not-found.segments/_head.segment.rsc +3 -3
- package/web/.next/server/app/_not-found.segments/_index.segment.rsc +6 -6
- package/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
- package/web/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
- package/web/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/web/.next/server/app/api/features/[id]/route/app-paths-manifest.json +3 -0
- package/web/.next/server/app/api/features/[id]/route/build-manifest.json +11 -0
- package/web/.next/server/app/api/features/[id]/route/server-reference-manifest.json +4 -0
- package/web/.next/server/app/api/features/[id]/route.js +7 -0
- package/web/.next/server/app/api/features/[id]/route.js.map +5 -0
- package/web/.next/server/app/api/features/[id]/route.js.nft.json +1 -0
- package/web/.next/server/app/api/features/[id]/route_client-reference-manifest.js +2 -0
- package/web/.next/server/app/api/features/create/route.js +1 -1
- package/web/.next/server/app/api/features/create/route.js.nft.json +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/app/version.html +2 -2
- package/web/.next/server/app/version.rsc +5 -5
- package/web/.next/server/app/version.segments/_full.segment.rsc +5 -5
- package/web/.next/server/app/version.segments/_head.segment.rsc +1 -1
- package/web/.next/server/app/version.segments/_index.segment.rsc +4 -4
- package/web/.next/server/app/version.segments/_tree.segment.rsc +2 -2
- package/web/.next/server/app/version.segments/version/__PAGE__.segment.rsc +2 -2
- package/web/.next/server/app/version.segments/version.segment.rsc +1 -1
- package/web/.next/server/app-paths-manifest.json +1 -0
- package/web/.next/server/chunks/403f9_next_dist_esm_build_templates_app-route_12059e3e.js.map +1 -1
- package/web/.next/server/chunks/744ca_web__next-internal_server_app_api_features_[id]_route_actions_03b9a4b5.js +3 -0
- package/web/.next/server/chunks/744ca_web__next-internal_server_app_api_features_[id]_route_actions_03b9a4b5.js.map +1 -0
- package/web/.next/server/chunks/[root-of-the-server]__0c45619b._.js +8 -0
- package/web/.next/server/chunks/[root-of-the-server]__0c45619b._.js.map +1 -0
- package/web/.next/server/chunks/[root-of-the-server]__25329f72._.js +3 -0
- package/web/.next/server/chunks/[root-of-the-server]__25329f72._.js.map +1 -0
- package/web/.next/server/chunks/ssr/[root-of-the-server]__f12b60be._.js +1 -1
- package/web/.next/server/chunks/ssr/_09afa42a._.js +12 -1
- package/web/.next/server/chunks/ssr/_09afa42a._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_a4189414._.js +10 -0
- package/web/.next/server/chunks/ssr/_a4189414._.js.map +1 -0
- 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/404.html +2 -2
- 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 +1 -1
- package/web/.next/static/chunks/1d665ddc2230f73f.js +5 -0
- package/web/.next/static/chunks/{fd961ef835ff4867.js → daacb9d30e4fc428.js} +13 -2
- package/web/.next/static/chunks/fd816afd85fd9a19.css +2 -0
- package/web/.next/trace +1 -1
- package/web/.next/trace-build +1 -1
- package/web/.next/types/link.d.ts +2 -1
- package/web/.next/types/routes.d.ts +2 -1
- package/web/.next/types/validator.ts +9 -0
- package/web/.next/server/chunks/[root-of-the-server]__4e987cf3._.js +0 -8
- package/web/.next/server/chunks/[root-of-the-server]__4e987cf3._.js.map +0 -1
- package/web/.next/server/chunks/ssr/_1c3962d7._.js +0 -10
- package/web/.next/server/chunks/ssr/_1c3962d7._.js.map +0 -1
- package/web/.next/static/chunks/79009d1ca0d944d2.js +0 -5
- package/web/.next/static/chunks/d8905884f147599c.css +0 -2
- /package/web/.next/static/{AmQVHj-yhxaqpAg8gC7MH → LkrVnyOa_e5oKSoKOC3uq}/_buildManifest.js +0 -0
- /package/web/.next/static/{AmQVHj-yhxaqpAg8gC7MH → LkrVnyOa_e5oKSoKOC3uq}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/static/{AmQVHj-yhxaqpAg8gC7MH → LkrVnyOa_e5oKSoKOC3uq}/_ssgManifest.js +0 -0
|
@@ -2,6 +2,8 @@ import type { FeatureNodeData } from '../../common/feature-node/index.js';
|
|
|
2
2
|
export interface FeatureDrawerProps {
|
|
3
3
|
selectedNode: FeatureNodeData | null;
|
|
4
4
|
onClose: () => void;
|
|
5
|
+
onDelete?: (featureId: string) => void;
|
|
6
|
+
isDeleting?: boolean;
|
|
5
7
|
}
|
|
6
|
-
export declare function FeatureDrawer({ selectedNode, onClose }: FeatureDrawerProps): import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
export declare function FeatureDrawer({ selectedNode, onClose, onDelete, isDeleting, }: FeatureDrawerProps): import("react/jsx-runtime").JSX.Element;
|
|
7
9
|
//# sourceMappingURL=feature-drawer.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"feature-drawer.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-drawer/feature-drawer.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"feature-drawer.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-drawer/feature-drawer.tsx"],"names":[],"mappings":"AA0BA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AAGxE,MAAM,WAAW,kBAAkB;IACjC,YAAY,EAAE,eAAe,GAAG,IAAI,CAAC;IACrC,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,wBAAgB,aAAa,CAAC,EAC5B,YAAY,EACZ,OAAO,EACP,QAAQ,EACR,UAAkB,GACnB,EAAE,kBAAkB,2CAyHpB"}
|
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
-
import { XIcon, Code2, Terminal, Loader2, CircleAlert } from 'lucide-react';
|
|
3
|
+
import { XIcon, Code2, Terminal, Loader2, CircleAlert, Trash2 } from 'lucide-react';
|
|
4
4
|
import { cn } from '../../../lib/utils.js';
|
|
5
5
|
import { Drawer, DrawerContent, DrawerHeader, DrawerTitle, DrawerDescription, } from '../../ui/drawer.js';
|
|
6
6
|
import { Button } from '../../ui/button.js';
|
|
7
7
|
import { Separator } from '../../ui/separator.js';
|
|
8
8
|
import { CometSpinner } from '../../ui/comet-spinner.js';
|
|
9
|
+
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger, } from '../../ui/alert-dialog.js';
|
|
9
10
|
import { featureNodeStateConfig, lifecycleDisplayLabels } from '../../common/feature-node/index.js';
|
|
10
11
|
import { useFeatureActions } from './use-feature-actions.js';
|
|
11
|
-
export function FeatureDrawer({ selectedNode, onClose }) {
|
|
12
|
+
export function FeatureDrawer({ selectedNode, onClose, onDelete, isDeleting = false, }) {
|
|
12
13
|
return (_jsx(Drawer, { direction: "right", modal: false, open: selectedNode !== null, onOpenChange: (open) => {
|
|
13
14
|
if (!open)
|
|
14
15
|
onClose();
|
|
15
|
-
}, children: _jsx(DrawerContent, { direction: "right", className: "w-96", showCloseButton: false, children: selectedNode ? (_jsxs(_Fragment, { children: [_jsx("button", { type: "button", "aria-label": "Close", onClick: onClose, className: "ring-offset-background focus:ring-ring absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden", children: _jsx(XIcon, { className: "size-4" }) }), _jsxs(DrawerHeader, { "data-testid": "feature-drawer-header", children: [_jsx(DrawerTitle, { children: selectedNode.name }), _jsx(DrawerDescription, { children: selectedNode.featureId })] }), selectedNode.repositoryPath && selectedNode.branch ? (_jsx(DrawerActions, { repositoryPath: selectedNode.repositoryPath, branch: selectedNode.branch })) : null, _jsx(Separator, {}), _jsxs("div", { "data-testid": "feature-drawer-status", className: "flex flex-col gap-3 p-4", children: [_jsx("div", { className: "text-muted-foreground text-xs font-semibold tracking-wider", children: lifecycleDisplayLabels[selectedNode.lifecycle] }), _jsx(StateBadge, { data: selectedNode }), selectedNode.progress > 0 ? (_jsxs("div", { "data-testid": "feature-drawer-progress", className: "flex flex-col gap-1", children: [_jsxs("div", { className: "text-muted-foreground flex items-center justify-between text-xs", children: [_jsx("span", { children: "Progress" }), _jsxs("span", { children: [selectedNode.progress, "%"] })] }), _jsx("div", { className: "bg-muted h-2 w-full overflow-hidden rounded-full", children: _jsx("div", { className: cn('h-full rounded-full transition-all', featureNodeStateConfig[selectedNode.state].progressClass), style: { width: `${selectedNode.progress}%` } }) })] })) : null] }), _jsx(Separator, {}), _jsx(DetailsSection, { data: selectedNode })] })) : null }) }));
|
|
16
|
+
}, children: _jsx(DrawerContent, { direction: "right", className: "w-96", showCloseButton: false, children: selectedNode ? (_jsxs(_Fragment, { children: [_jsx("button", { type: "button", "aria-label": "Close", onClick: onClose, className: "ring-offset-background focus:ring-ring absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden", children: _jsx(XIcon, { className: "size-4" }) }), _jsxs(DrawerHeader, { "data-testid": "feature-drawer-header", children: [_jsx(DrawerTitle, { children: selectedNode.name }), _jsx(DrawerDescription, { children: selectedNode.featureId })] }), selectedNode.repositoryPath && selectedNode.branch ? (_jsx(DrawerActions, { repositoryPath: selectedNode.repositoryPath, branch: selectedNode.branch })) : null, _jsx(Separator, {}), _jsxs("div", { "data-testid": "feature-drawer-status", className: "flex flex-col gap-3 p-4", children: [_jsx("div", { className: "text-muted-foreground text-xs font-semibold tracking-wider", children: lifecycleDisplayLabels[selectedNode.lifecycle] }), _jsx(StateBadge, { data: selectedNode }), selectedNode.progress > 0 ? (_jsxs("div", { "data-testid": "feature-drawer-progress", className: "flex flex-col gap-1", children: [_jsxs("div", { className: "text-muted-foreground flex items-center justify-between text-xs", children: [_jsx("span", { children: "Progress" }), _jsxs("span", { children: [selectedNode.progress, "%"] })] }), _jsx("div", { className: "bg-muted h-2 w-full overflow-hidden rounded-full", children: _jsx("div", { className: cn('h-full rounded-full transition-all', featureNodeStateConfig[selectedNode.state].progressClass), style: { width: `${selectedNode.progress}%` } }) })] })) : null] }), _jsx(Separator, {}), _jsx(DetailsSection, { data: selectedNode }), onDelete ? (_jsxs(_Fragment, { children: [_jsx(Separator, {}), _jsx("div", { "data-testid": "feature-drawer-delete", className: "p-4", children: _jsxs(AlertDialog, { children: [_jsx(AlertDialogTrigger, { asChild: true, children: _jsxs(Button, { variant: "destructive", className: "w-full", disabled: isDeleting, children: [_jsx(Trash2, { className: "mr-2 h-4 w-4" }), "Delete feature"] }) }), _jsxs(AlertDialogContent, { children: [_jsxs(AlertDialogHeader, { children: [_jsx(AlertDialogTitle, { children: "Delete feature?" }), _jsxs(AlertDialogDescription, { children: ["This will permanently delete ", _jsx("strong", { children: selectedNode.name }), " (", selectedNode.featureId, "). This action cannot be undone.", selectedNode.state === 'running' ? (_jsx(_Fragment, { children: " This feature has a running agent that will be stopped." })) : null] })] }), _jsxs(AlertDialogFooter, { children: [_jsx(AlertDialogCancel, { disabled: isDeleting, children: "Cancel" }), _jsx(AlertDialogAction, { variant: "destructive", disabled: isDeleting, onClick: () => onDelete(selectedNode.featureId), children: isDeleting ? (_jsxs(_Fragment, { children: [_jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), "Deleting\u2026"] })) : ('Delete') })] })] })] }) })] })) : null] })) : null }) }));
|
|
16
17
|
}
|
|
17
18
|
function StateBadge({ data }) {
|
|
18
19
|
const config = featureNodeStateConfig[data.state];
|
package/dist/src/presentation/web/components/common/feature-drawer/feature-drawer.stories.d.ts
CHANGED
|
@@ -24,4 +24,10 @@ export declare const NoRepositoryPath: Story;
|
|
|
24
24
|
* (API routes are not available in Storybook).
|
|
25
25
|
*/
|
|
26
26
|
export declare const WithActionButtons: Story;
|
|
27
|
+
/** FeatureDrawer with a delete button in the footer. */
|
|
28
|
+
export declare const WithDeleteButton: Story;
|
|
29
|
+
/** FeatureDrawer showing the delete button in loading/disabled state. */
|
|
30
|
+
export declare const DeletingState: Story;
|
|
31
|
+
/** FeatureDrawer with a running agent showing the running-agent warning in the AlertDialog. */
|
|
32
|
+
export declare const DeleteRunningAgent: Story;
|
|
27
33
|
//# sourceMappingURL=feature-drawer.stories.d.ts.map
|
package/dist/src/presentation/web/components/common/feature-drawer/feature-drawer.stories.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"feature-drawer.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-drawer/feature-drawer.stories.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAKjD,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,aAAa,CAOpC,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,aAAa,CAAC,CAAC;AAgG5C,eAAO,MAAM,OAAO,EAAE,KAErB,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,KAE5B,CAAC;AAEF,eAAO,MAAM,IAAI,EAAE,KAElB,CAAC;AAEF,eAAO,MAAM,OAAO,EAAE,KAErB,CAAC;AAEF,eAAO,MAAM,KAAK,EAAE,KAEnB,CAAC;AAMF,wEAAwE;AACxE,eAAO,MAAM,WAAW,EAAE,KAEzB,CAAC;AAEF,qFAAqF;AACrF,eAAO,MAAM,SAAS,EAAE,KAqBvB,CAAC;AAuDF,0DAA0D;AAC1D,eAAO,MAAM,SAAS,EAAE,KAEvB,CAAC;AA6CF,wDAAwD;AACxD,eAAO,MAAM,aAAa,EAAE,KAE3B,CAAC;AAMF,qDAAqD;AACrD,eAAO,MAAM,gBAAgB,EAAE,KAO9B,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,EAAE,KAE/B,CAAC"}
|
|
1
|
+
{"version":3,"file":"feature-drawer.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-drawer/feature-drawer.stories.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAKjD,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,aAAa,CAOpC,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,aAAa,CAAC,CAAC;AAgG5C,eAAO,MAAM,OAAO,EAAE,KAErB,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,KAE5B,CAAC;AAEF,eAAO,MAAM,IAAI,EAAE,KAElB,CAAC;AAEF,eAAO,MAAM,OAAO,EAAE,KAErB,CAAC;AAEF,eAAO,MAAM,KAAK,EAAE,KAEnB,CAAC;AAMF,wEAAwE;AACxE,eAAO,MAAM,WAAW,EAAE,KAEzB,CAAC;AAEF,qFAAqF;AACrF,eAAO,MAAM,SAAS,EAAE,KAqBvB,CAAC;AAuDF,0DAA0D;AAC1D,eAAO,MAAM,SAAS,EAAE,KAEvB,CAAC;AA6CF,wDAAwD;AACxD,eAAO,MAAM,aAAa,EAAE,KAE3B,CAAC;AAMF,qDAAqD;AACrD,eAAO,MAAM,gBAAgB,EAAE,KAO9B,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,EAAE,KAE/B,CAAC;AAoCF,wDAAwD;AACxD,eAAO,MAAM,gBAAgB,EAAE,KAE9B,CAAC;AAEF,yEAAyE;AACzE,eAAO,MAAM,aAAa,EAAE,KAE3B,CAAC;AAEF,+FAA+F;AAC/F,eAAO,MAAM,kBAAkB,EAAE,KAEhC,CAAC"}
|
package/dist/src/presentation/web/components/common/feature-drawer/feature-drawer.stories.js
CHANGED
|
@@ -196,3 +196,25 @@ export const NoRepositoryPath = {
|
|
|
196
196
|
export const WithActionButtons = {
|
|
197
197
|
render: () => _jsx(DrawerTrigger, { data: runningData, label: "Open With Actions" }),
|
|
198
198
|
};
|
|
199
|
+
/* ---------------------------------------------------------------------------
|
|
200
|
+
* Delete stories
|
|
201
|
+
* ------------------------------------------------------------------------- */
|
|
202
|
+
function noop() {
|
|
203
|
+
// intentional no-op for stories
|
|
204
|
+
}
|
|
205
|
+
function DrawerTriggerWithDelete({ data, label, isDeleting = false, }) {
|
|
206
|
+
const [selected, setSelected] = useState(null);
|
|
207
|
+
return (_jsxs("div", { className: "flex h-screen items-start p-4", children: [_jsx(Button, { variant: "outline", onClick: () => setSelected(data), children: label }), _jsx(FeatureDrawer, { selectedNode: selected, onClose: () => setSelected(null), onDelete: noop, isDeleting: isDeleting })] }));
|
|
208
|
+
}
|
|
209
|
+
/** FeatureDrawer with a delete button in the footer. */
|
|
210
|
+
export const WithDeleteButton = {
|
|
211
|
+
render: () => _jsx(DrawerTriggerWithDelete, { data: doneData, label: "Open With Delete" }),
|
|
212
|
+
};
|
|
213
|
+
/** FeatureDrawer showing the delete button in loading/disabled state. */
|
|
214
|
+
export const DeletingState = {
|
|
215
|
+
render: () => _jsx(DrawerTriggerWithDelete, { data: doneData, label: "Open Deleting State", isDeleting: true }),
|
|
216
|
+
};
|
|
217
|
+
/** FeatureDrawer with a running agent showing the running-agent warning in the AlertDialog. */
|
|
218
|
+
export const DeleteRunningAgent = {
|
|
219
|
+
render: () => _jsx(DrawerTriggerWithDelete, { data: runningData, label: "Open Running Agent Delete" }),
|
|
220
|
+
};
|
package/dist/src/presentation/web/components/common/feature-node/feature-node.stories.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"feature-node.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-node/feature-node.stories.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAIvD,OAAO,KAAK,EACV,eAAe,EAIhB,MAAM,6BAA6B,CAAC;AAiCrC,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,eAAe,CAe/B,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,eAAe,CAAC,CAAC;AAEvC,eAAO,MAAM,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"feature-node.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-node/feature-node.stories.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAIvD,OAAO,KAAK,EACV,eAAe,EAIhB,MAAM,6BAA6B,CAAC;AAiCrC,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,eAAe,CAe/B,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,eAAe,CAAC,CAAC;AAEvC,eAAO,MAAM,OAAO,EAAE,KAMrB,CAAC;AA2DF,eAAO,MAAM,SAAS,EAAE,KAQvB,CAAC;AAWF,eAAO,MAAM,aAAa,EAAE,KAsB3B,CAAC;AAEF,eAAO,MAAM,UAAU,EAAE,KAMxB,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,KAOzB,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,KAW7B,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,KAW9B,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,KAW9B,CAAC;AA6EF,eAAO,MAAM,WAAW,EAAE,KAOzB,CAAC"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { AddRepositoryNode, type AddRepositoryNodeData, type AddRepositoryNodeType, } from './add-repository-node/index.js';
|
|
2
2
|
export { ElapsedTime, formatElapsed } from './elapsed-time/index.js';
|
|
3
3
|
export { EmptyState, type EmptyStateProps } from './empty-state/index.js';
|
|
4
|
-
export { FeatureCreateDrawer, type FeatureCreateDrawerProps
|
|
4
|
+
export { FeatureCreateDrawer, type FeatureCreateDrawerProps } from './feature-create-drawer/index.js';
|
|
5
5
|
export { FeatureDrawer, type FeatureDrawerProps } from './feature-drawer/index.js';
|
|
6
6
|
export { FeatureListItem, type FeatureListItemProps } from './feature-list-item/index.js';
|
|
7
7
|
export { useFeatureActions, type FeatureActionsInput, type FeatureActionsState, } from './feature-drawer/use-feature-actions.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/web/components/common/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,KAAK,qBAAqB,EAC1B,KAAK,qBAAqB,GAC3B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC5D,OAAO,EAAE,UAAU,EAAE,KAAK,eAAe,EAAE,MAAM,eAAe,CAAC;AACjE,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/web/components/common/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,KAAK,qBAAqB,EAC1B,KAAK,qBAAqB,GAC3B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC5D,OAAO,EAAE,UAAU,EAAE,KAAK,eAAe,EAAE,MAAM,eAAe,CAAC;AACjE,OAAO,EAAE,mBAAmB,EAAE,KAAK,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AAC7F,OAAO,EAAE,aAAa,EAAE,KAAK,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAC1E,OAAO,EAAE,eAAe,EAAE,KAAK,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AACjF,OAAO,EACL,iBAAiB,EACjB,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,GACzB,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EACL,WAAW,EACX,sBAAsB,EACtB,KAAK,gBAAgB,EACrB,KAAK,qBAAqB,EAC1B,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,KAAK,sBAAsB,GAC5B,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,mBAAmB,EAAE,KAAK,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AAC7F,OAAO,EAAE,kBAAkB,EAAE,KAAK,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAC1F,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EACL,cAAc,EACd,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,GACxB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAC3D,OAAO,EAAE,qBAAqB,EAAE,KAAK,0BAA0B,EAAE,MAAM,2BAA2B,CAAC;AACnG,OAAO,EAAE,cAAc,EAAE,KAAK,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC9E,OAAO,EAAE,oBAAoB,EAAE,KAAK,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AAChG,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { AddRepositoryNode, } from './add-repository-node/index.js';
|
|
2
2
|
export { ElapsedTime, formatElapsed } from './elapsed-time/index.js';
|
|
3
3
|
export { EmptyState } from './empty-state/index.js';
|
|
4
|
-
export { FeatureCreateDrawer
|
|
4
|
+
export { FeatureCreateDrawer } from './feature-create-drawer/index.js';
|
|
5
5
|
export { FeatureDrawer } from './feature-drawer/index.js';
|
|
6
6
|
export { FeatureListItem } from './feature-list-item/index.js';
|
|
7
7
|
export { useFeatureActions, } from './feature-drawer/use-feature-actions.js';
|
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;AAE1C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAK5E,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,
|
|
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;AAE1C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAK5E,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,2CA2DzF"}
|
package/dist/src/presentation/web/components/features/control-center/control-center-inner.js
CHANGED
|
@@ -6,12 +6,12 @@ import { FeatureDrawer, FeatureCreateDrawer } from '../../common/index.js';
|
|
|
6
6
|
import { ControlCenterEmptyState } from './control-center-empty-state.js';
|
|
7
7
|
import { useControlCenterState } from './use-control-center-state.js';
|
|
8
8
|
export function ControlCenterInner({ initialNodes, initialEdges }) {
|
|
9
|
-
const { nodes, edges, selectedNode, isCreateDrawerOpen, isSubmitting, onNodesChange, handleConnect, handleAddFeature, handleAddFeatureToRepo, handleAddFeatureToFeature, handleAddRepository, handleNodeClick, clearSelection, handleCreateFeatureSubmit, closeCreateDrawer, } = useControlCenterState(initialNodes, initialEdges);
|
|
9
|
+
const { nodes, edges, selectedNode, isCreateDrawerOpen, isSubmitting, isDeleting, pendingRepositoryPath, onNodesChange, handleConnect, handleAddFeature, handleAddFeatureToRepo, handleAddFeatureToFeature, handleAddRepository, handleNodeClick, clearSelection, handleCreateFeatureSubmit, handleDeleteFeature, closeCreateDrawer, } = useControlCenterState(initialNodes, initialEdges);
|
|
10
10
|
// Listen for global "open create drawer" events from the sidebar
|
|
11
11
|
useEffect(() => {
|
|
12
12
|
const handler = () => handleAddFeature();
|
|
13
13
|
window.addEventListener('shep:open-create-drawer', handler);
|
|
14
14
|
return () => window.removeEventListener('shep:open-create-drawer', handler);
|
|
15
15
|
}, [handleAddFeature]);
|
|
16
|
-
return (_jsxs(_Fragment, { children: [_jsx(FeaturesCanvas, { nodes: nodes, edges: edges, onNodesChange: onNodesChange, onConnect: handleConnect, onAddFeature: handleAddFeature, onNodeAction: handleAddFeatureToFeature, onNodeClick: handleNodeClick, onPaneClick: clearSelection, onRepositoryAdd: handleAddFeatureToRepo, onRepositorySelect: handleAddRepository, emptyState: _jsx(ControlCenterEmptyState, { onRepositorySelect: handleAddRepository }) }), _jsx(FeatureDrawer, { selectedNode: selectedNode, onClose: clearSelection }), _jsx(FeatureCreateDrawer, { open: isCreateDrawerOpen, onClose: closeCreateDrawer, onSubmit: handleCreateFeatureSubmit, isSubmitting: isSubmitting })] }));
|
|
16
|
+
return (_jsxs(_Fragment, { children: [_jsx(FeaturesCanvas, { nodes: nodes, edges: edges, onNodesChange: onNodesChange, onConnect: handleConnect, onAddFeature: handleAddFeature, onNodeAction: handleAddFeatureToFeature, onNodeClick: handleNodeClick, onPaneClick: clearSelection, onRepositoryAdd: handleAddFeatureToRepo, onRepositorySelect: handleAddRepository, emptyState: _jsx(ControlCenterEmptyState, { onRepositorySelect: handleAddRepository }) }), _jsx(FeatureDrawer, { selectedNode: selectedNode, onClose: clearSelection, onDelete: handleDeleteFeature, isDeleting: isDeleting }), _jsx(FeatureCreateDrawer, { open: isCreateDrawerOpen, onClose: closeCreateDrawer, onSubmit: handleCreateFeatureSubmit, repositoryPath: pendingRepositoryPath, isSubmitting: isSubmitting })] }));
|
|
17
17
|
}
|
package/dist/src/presentation/web/components/features/control-center/use-control-center-state.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Connection, Edge, NodeChange } from '@xyflow/react';
|
|
2
2
|
import type { FeatureNodeData } from '../../common/feature-node/index.js';
|
|
3
|
-
import type {
|
|
3
|
+
import type { CreateFeatureInput } from '../../../../../../packages/core/src/infrastructure/di/use-cases-bridge.js';
|
|
4
4
|
import type { CanvasNodeType } from '../../features/features-canvas/index.js';
|
|
5
5
|
import { type LayoutDirection } from '../../../lib/layout-with-dagre.js';
|
|
6
6
|
export interface ControlCenterState {
|
|
@@ -9,6 +9,7 @@ export interface ControlCenterState {
|
|
|
9
9
|
selectedNode: FeatureNodeData | null;
|
|
10
10
|
isCreateDrawerOpen: boolean;
|
|
11
11
|
isSubmitting: boolean;
|
|
12
|
+
pendingRepositoryPath: string;
|
|
12
13
|
onNodesChange: (changes: NodeChange<CanvasNodeType>[]) => void;
|
|
13
14
|
handleConnect: (connection: Connection) => void;
|
|
14
15
|
clearSelection: () => void;
|
|
@@ -18,8 +19,10 @@ export interface ControlCenterState {
|
|
|
18
19
|
handleAddFeatureToFeature: (featureNodeId: string) => void;
|
|
19
20
|
handleAddRepository: (path: string) => void;
|
|
20
21
|
handleLayout: (direction: LayoutDirection) => void;
|
|
21
|
-
handleCreateFeatureSubmit: (data:
|
|
22
|
+
handleCreateFeatureSubmit: (data: CreateFeatureInput) => void;
|
|
22
23
|
closeCreateDrawer: () => void;
|
|
24
|
+
handleDeleteFeature: (featureId: string) => Promise<void>;
|
|
25
|
+
isDeleting: boolean;
|
|
23
26
|
}
|
|
24
27
|
export declare function useControlCenterState(initialNodes: CanvasNodeType[], initialEdges: Edge[]): ControlCenterState;
|
|
25
28
|
//# sourceMappingURL=use-control-center-state.d.ts.map
|
|
@@ -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,
|
|
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,kBAAkB,EAAE,MAAM,iDAAiD,CAAC;AAC1F,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAC5E,OAAO,EAAmB,KAAK,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAEhF,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,YAAY,EAAE,OAAO,CAAC;IACtB,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,kBAAkB,KAAK,IAAI,CAAC;IAC9D,iBAAiB,EAAE,MAAM,IAAI,CAAC;IAC9B,mBAAmB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1D,UAAU,EAAE,OAAO,CAAC;CACrB;AAID,wBAAgB,qBAAqB,CACnC,YAAY,EAAE,cAAc,EAAE,EAC9B,YAAY,EAAE,IAAI,EAAE,GACnB,kBAAkB,CA2UpB"}
|
package/dist/src/presentation/web/components/features/control-center/use-control-center-state.js
CHANGED
|
@@ -12,6 +12,7 @@ export function useControlCenterState(initialNodes, initialEdges) {
|
|
|
12
12
|
const [selectedNode, setSelectedNode] = useState(null);
|
|
13
13
|
const [isCreateDrawerOpen, setIsCreateDrawerOpen] = useState(false);
|
|
14
14
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
15
|
+
const [isDeleting, setIsDeleting] = useState(false);
|
|
15
16
|
const [pendingRepoNodeId, setPendingRepoNodeId] = useState(null);
|
|
16
17
|
const onNodesChange = useCallback((changes) => {
|
|
17
18
|
setNodes((ns) => applyNodeChanges(changes, ns));
|
|
@@ -169,22 +170,12 @@ export function useControlCenterState(initialNodes, initialEdges) {
|
|
|
169
170
|
setIsCreateDrawerOpen(true);
|
|
170
171
|
}, []);
|
|
171
172
|
const handleCreateFeatureSubmit = useCallback(async (data) => {
|
|
172
|
-
if (!pendingRepoNodeId) {
|
|
173
|
-
toast.error('Please create the feature from a repository node.');
|
|
174
|
-
return;
|
|
175
|
-
}
|
|
176
|
-
const repositoryPath = pendingRepoNodeId.replace(/^repo-/, '');
|
|
177
173
|
setIsSubmitting(true);
|
|
178
174
|
try {
|
|
179
175
|
const response = await fetch('/api/features/create', {
|
|
180
176
|
method: 'POST',
|
|
181
177
|
headers: { 'Content-Type': 'application/json' },
|
|
182
|
-
body: JSON.stringify(
|
|
183
|
-
name: data.name,
|
|
184
|
-
description: data.description || '',
|
|
185
|
-
repositoryPath,
|
|
186
|
-
attachments: data.attachments,
|
|
187
|
-
}),
|
|
178
|
+
body: JSON.stringify(data),
|
|
188
179
|
});
|
|
189
180
|
if (!response.ok) {
|
|
190
181
|
const body = await response.json();
|
|
@@ -202,10 +193,34 @@ export function useControlCenterState(initialNodes, initialEdges) {
|
|
|
202
193
|
finally {
|
|
203
194
|
setIsSubmitting(false);
|
|
204
195
|
}
|
|
205
|
-
}, [
|
|
196
|
+
}, [router]);
|
|
206
197
|
const closeCreateDrawer = useCallback(() => {
|
|
207
198
|
setIsCreateDrawerOpen(false);
|
|
208
199
|
}, []);
|
|
200
|
+
const handleDeleteFeature = useCallback(async (featureId) => {
|
|
201
|
+
setIsDeleting(true);
|
|
202
|
+
try {
|
|
203
|
+
const response = await fetch(`/api/features/${featureId}`, {
|
|
204
|
+
method: 'DELETE',
|
|
205
|
+
});
|
|
206
|
+
if (!response.ok) {
|
|
207
|
+
const body = await response.json();
|
|
208
|
+
toast.error(body.error ?? 'Failed to delete feature');
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
setSelectedNode(null);
|
|
212
|
+
setNodes((prev) => prev.filter((n) => n.id !== featureId));
|
|
213
|
+
setEdges((prev) => prev.filter((e) => e.source !== featureId && e.target !== featureId));
|
|
214
|
+
toast.success('Feature deleted successfully');
|
|
215
|
+
router.refresh();
|
|
216
|
+
}
|
|
217
|
+
catch {
|
|
218
|
+
toast.error('Failed to delete feature');
|
|
219
|
+
}
|
|
220
|
+
finally {
|
|
221
|
+
setIsDeleting(false);
|
|
222
|
+
}
|
|
223
|
+
}, [router]);
|
|
209
224
|
const handleAddFeatureToRepo = useCallback((repoNodeId) => {
|
|
210
225
|
setSelectedNode(null);
|
|
211
226
|
setPendingRepoNodeId(repoNodeId);
|
|
@@ -252,12 +267,14 @@ export function useControlCenterState(initialNodes, initialEdges) {
|
|
|
252
267
|
.concat(newNode);
|
|
253
268
|
});
|
|
254
269
|
}, []);
|
|
270
|
+
const pendingRepositoryPath = pendingRepoNodeId?.replace(/^repo-/, '') ?? '';
|
|
255
271
|
return {
|
|
256
272
|
nodes,
|
|
257
273
|
edges,
|
|
258
274
|
selectedNode,
|
|
259
275
|
isCreateDrawerOpen,
|
|
260
276
|
isSubmitting,
|
|
277
|
+
pendingRepositoryPath,
|
|
261
278
|
onNodesChange,
|
|
262
279
|
handleConnect,
|
|
263
280
|
clearSelection,
|
|
@@ -269,5 +286,7 @@ export function useControlCenterState(initialNodes, initialEdges) {
|
|
|
269
286
|
handleLayout,
|
|
270
287
|
handleCreateFeatureSubmit,
|
|
271
288
|
closeCreateDrawer,
|
|
289
|
+
handleDeleteFeature,
|
|
290
|
+
isDeleting,
|
|
272
291
|
};
|
|
273
292
|
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { AlertDialog as AlertDialogPrimitive } from 'radix-ui';
|
|
3
|
+
import { Button } from '../ui/button.js';
|
|
4
|
+
declare function AlertDialog({ ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Root>): import("react/jsx-runtime").JSX.Element;
|
|
5
|
+
declare function AlertDialogTrigger({ ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Trigger>): import("react/jsx-runtime").JSX.Element;
|
|
6
|
+
declare function AlertDialogPortal({ ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Portal>): import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
declare function AlertDialogOverlay({ className, ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Overlay>): import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
declare function AlertDialogContent({ className, size, ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Content> & {
|
|
9
|
+
size?: 'default' | 'sm';
|
|
10
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
11
|
+
declare function AlertDialogHeader({ className, ...props }: React.ComponentProps<'div'>): import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
declare function AlertDialogFooter({ className, ...props }: React.ComponentProps<'div'>): import("react/jsx-runtime").JSX.Element;
|
|
13
|
+
declare function AlertDialogTitle({ className, ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Title>): import("react/jsx-runtime").JSX.Element;
|
|
14
|
+
declare function AlertDialogDescription({ className, ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Description>): import("react/jsx-runtime").JSX.Element;
|
|
15
|
+
declare function AlertDialogMedia({ className, ...props }: React.ComponentProps<'div'>): import("react/jsx-runtime").JSX.Element;
|
|
16
|
+
declare function AlertDialogAction({ className, variant, size, ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Action> & Pick<React.ComponentProps<typeof Button>, 'variant' | 'size'>): import("react/jsx-runtime").JSX.Element;
|
|
17
|
+
declare function AlertDialogCancel({ className, variant, size, ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Cancel> & Pick<React.ComponentProps<typeof Button>, 'variant' | 'size'>): import("react/jsx-runtime").JSX.Element;
|
|
18
|
+
export { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogMedia, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, };
|
|
19
|
+
//# sourceMappingURL=alert-dialog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"alert-dialog.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/web/components/ui/alert-dialog.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,WAAW,IAAI,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAG/D,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAEhD,iBAAS,WAAW,CAAC,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,oBAAoB,CAAC,IAAI,CAAC,2CAExF;AAED,iBAAS,kBAAkB,CAAC,EAC1B,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,oBAAoB,CAAC,OAAO,CAAC,2CAE3D;AAED,iBAAS,iBAAiB,CAAC,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,oBAAoB,CAAC,MAAM,CAAC,2CAEhG;AAED,iBAAS,kBAAkB,CAAC,EAC1B,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,oBAAoB,CAAC,OAAO,CAAC,2CAW3D;AAED,iBAAS,kBAAkB,CAAC,EAC1B,SAAS,EACT,IAAgB,EAChB,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,oBAAoB,CAAC,OAAO,CAAC,GAAG;IAC7D,IAAI,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;CACzB,2CAeA;AAED,iBAAS,iBAAiB,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,2CAW9E;AAED,iBAAS,iBAAiB,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,2CAW9E;AAED,iBAAS,gBAAgB,CAAC,EACxB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,oBAAoB,CAAC,KAAK,CAAC,2CAWzD;AAED,iBAAS,sBAAsB,CAAC,EAC9B,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,oBAAoB,CAAC,WAAW,CAAC,2CAQ/D;AAED,iBAAS,gBAAgB,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,2CAW7E;AAED,iBAAS,iBAAiB,CAAC,EACzB,SAAS,EACT,OAAmB,EACnB,IAAgB,EAChB,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,oBAAoB,CAAC,MAAM,CAAC,GACzD,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,MAAM,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC,2CAU9D;AAED,iBAAS,iBAAiB,CAAC,EACzB,SAAS,EACT,OAAmB,EACnB,IAAgB,EAChB,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,oBAAoB,CAAC,MAAM,CAAC,GACzD,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,MAAM,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC,2CAU9D;AAED,OAAO,EACL,WAAW,EACX,iBAAiB,EACjB,iBAAiB,EACjB,kBAAkB,EAClB,sBAAsB,EACtB,iBAAiB,EACjB,iBAAiB,EACjB,gBAAgB,EAChB,kBAAkB,EAClB,iBAAiB,EACjB,gBAAgB,EAChB,kBAAkB,GACnB,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { AlertDialog as AlertDialogPrimitive } from 'radix-ui';
|
|
4
|
+
import { cn } from '../../lib/utils.js';
|
|
5
|
+
import { Button } from '../ui/button.js';
|
|
6
|
+
function AlertDialog({ ...props }) {
|
|
7
|
+
return _jsx(AlertDialogPrimitive.Root, { "data-slot": "alert-dialog", ...props });
|
|
8
|
+
}
|
|
9
|
+
function AlertDialogTrigger({ ...props }) {
|
|
10
|
+
return _jsx(AlertDialogPrimitive.Trigger, { "data-slot": "alert-dialog-trigger", ...props });
|
|
11
|
+
}
|
|
12
|
+
function AlertDialogPortal({ ...props }) {
|
|
13
|
+
return _jsx(AlertDialogPrimitive.Portal, { "data-slot": "alert-dialog-portal", ...props });
|
|
14
|
+
}
|
|
15
|
+
function AlertDialogOverlay({ className, ...props }) {
|
|
16
|
+
return (_jsx(AlertDialogPrimitive.Overlay, { "data-slot": "alert-dialog-overlay", className: cn('data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50', className), ...props }));
|
|
17
|
+
}
|
|
18
|
+
function AlertDialogContent({ className, size = 'default', ...props }) {
|
|
19
|
+
return (_jsxs(AlertDialogPortal, { children: [_jsx(AlertDialogOverlay, {}), _jsx(AlertDialogPrimitive.Content, { "data-slot": "alert-dialog-content", "data-size": size, className: cn('bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 group/alert-dialog-content fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 data-[size=sm]:max-w-xs data-[size=default]:sm:max-w-lg', className), ...props })] }));
|
|
20
|
+
}
|
|
21
|
+
function AlertDialogHeader({ className, ...props }) {
|
|
22
|
+
return (_jsx("div", { "data-slot": "alert-dialog-header", className: cn('grid grid-rows-[auto_1fr] place-items-center gap-1.5 text-center has-data-[slot=alert-dialog-media]:grid-rows-[auto_auto_1fr] has-data-[slot=alert-dialog-media]:gap-x-6 sm:group-data-[size=default]/alert-dialog-content:place-items-start sm:group-data-[size=default]/alert-dialog-content:text-left sm:group-data-[size=default]/alert-dialog-content:has-data-[slot=alert-dialog-media]:grid-rows-[auto_1fr]', className), ...props }));
|
|
23
|
+
}
|
|
24
|
+
function AlertDialogFooter({ className, ...props }) {
|
|
25
|
+
return (_jsx("div", { "data-slot": "alert-dialog-footer", className: cn('flex flex-col-reverse gap-2 group-data-[size=sm]/alert-dialog-content:grid group-data-[size=sm]/alert-dialog-content:grid-cols-2 sm:flex-row sm:justify-end', className), ...props }));
|
|
26
|
+
}
|
|
27
|
+
function AlertDialogTitle({ className, ...props }) {
|
|
28
|
+
return (_jsx(AlertDialogPrimitive.Title, { "data-slot": "alert-dialog-title", className: cn('text-lg font-semibold sm:group-data-[size=default]/alert-dialog-content:group-has-data-[slot=alert-dialog-media]/alert-dialog-content:col-start-2', className), ...props }));
|
|
29
|
+
}
|
|
30
|
+
function AlertDialogDescription({ className, ...props }) {
|
|
31
|
+
return (_jsx(AlertDialogPrimitive.Description, { "data-slot": "alert-dialog-description", className: cn('text-muted-foreground text-sm', className), ...props }));
|
|
32
|
+
}
|
|
33
|
+
function AlertDialogMedia({ className, ...props }) {
|
|
34
|
+
return (_jsx("div", { "data-slot": "alert-dialog-media", className: cn("bg-muted mb-2 inline-flex size-16 items-center justify-center rounded-md sm:group-data-[size=default]/alert-dialog-content:row-span-2 *:[svg:not([class*='size-'])]:size-8", className), ...props }));
|
|
35
|
+
}
|
|
36
|
+
function AlertDialogAction({ className, variant = 'default', size = 'default', ...props }) {
|
|
37
|
+
return (_jsx(Button, { variant: variant, size: size, asChild: true, children: _jsx(AlertDialogPrimitive.Action, { "data-slot": "alert-dialog-action", className: cn(className), ...props }) }));
|
|
38
|
+
}
|
|
39
|
+
function AlertDialogCancel({ className, variant = 'outline', size = 'default', ...props }) {
|
|
40
|
+
return (_jsx(Button, { variant: variant, size: size, asChild: true, children: _jsx(AlertDialogPrimitive.Cancel, { "data-slot": "alert-dialog-cancel", className: cn(className), ...props }) }));
|
|
41
|
+
}
|
|
42
|
+
export { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogMedia, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { AlertDialog } from './alert-dialog.js';
|
|
3
|
+
declare const meta: Meta<typeof AlertDialog>;
|
|
4
|
+
export default meta;
|
|
5
|
+
type Story = StoryObj<typeof meta>;
|
|
6
|
+
export declare const Default: Story;
|
|
7
|
+
export declare const DestructiveAction: Story;
|
|
8
|
+
export declare const WithDescription: Story;
|
|
9
|
+
//# sourceMappingURL=alert-dialog.stories.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"alert-dialog.stories.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/web/components/ui/alert-dialog.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EACL,WAAW,EASZ,MAAM,gBAAgB,CAAC;AAGxB,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,WAAW,CAOlC,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,IAAI,CAAC,CAAC;AAEnC,eAAO,MAAM,OAAO,EAAE,KAoBrB,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,KAqB/B,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,KAqB7B,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger, } from './alert-dialog.js';
|
|
3
|
+
import { Button } from './button.js';
|
|
4
|
+
const meta = {
|
|
5
|
+
title: 'Primitives/AlertDialog',
|
|
6
|
+
component: AlertDialog,
|
|
7
|
+
parameters: {
|
|
8
|
+
layout: 'centered',
|
|
9
|
+
},
|
|
10
|
+
tags: ['autodocs'],
|
|
11
|
+
};
|
|
12
|
+
export default meta;
|
|
13
|
+
export const Default = {
|
|
14
|
+
render: () => (_jsxs(AlertDialog, { children: [_jsx(AlertDialogTrigger, { asChild: true, children: _jsx(Button, { variant: "outline", children: "Show Dialog" }) }), _jsxs(AlertDialogContent, { children: [_jsxs(AlertDialogHeader, { children: [_jsx(AlertDialogTitle, { children: "Are you sure?" }), _jsx(AlertDialogDescription, { children: "This action cannot be undone. This will permanently apply the changes." })] }), _jsxs(AlertDialogFooter, { children: [_jsx(AlertDialogCancel, { children: "Cancel" }), _jsx(AlertDialogAction, { children: "Continue" })] })] })] })),
|
|
15
|
+
};
|
|
16
|
+
export const DestructiveAction = {
|
|
17
|
+
render: () => (_jsxs(AlertDialog, { children: [_jsx(AlertDialogTrigger, { asChild: true, children: _jsx(Button, { variant: "destructive", children: "Delete Account" }) }), _jsxs(AlertDialogContent, { children: [_jsxs(AlertDialogHeader, { children: [_jsx(AlertDialogTitle, { children: "Delete account?" }), _jsx(AlertDialogDescription, { children: "This will permanently delete your account and remove all associated data. This action cannot be undone." })] }), _jsxs(AlertDialogFooter, { children: [_jsx(AlertDialogCancel, { children: "Cancel" }), _jsx(AlertDialogAction, { variant: "destructive", children: "Delete" })] })] })] })),
|
|
18
|
+
};
|
|
19
|
+
export const WithDescription = {
|
|
20
|
+
render: () => (_jsxs(AlertDialog, { children: [_jsx(AlertDialogTrigger, { asChild: true, children: _jsx(Button, { variant: "outline", children: "Discard Changes" }) }), _jsxs(AlertDialogContent, { children: [_jsxs(AlertDialogHeader, { children: [_jsx(AlertDialogTitle, { children: "Discard unsaved changes?" }), _jsxs(AlertDialogDescription, { children: ["You have unsaved changes in ", _jsx("strong", { children: "3 files" }), ". If you discard now, all changes will be lost and cannot be recovered."] })] }), _jsxs(AlertDialogFooter, { children: [_jsx(AlertDialogCancel, { children: "Keep Editing" }), _jsx(AlertDialogAction, { variant: "destructive", children: "Discard" })] })] })] })),
|
|
21
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface CheckboxGroupItemProps {
|
|
2
|
+
id: string;
|
|
3
|
+
label: string;
|
|
4
|
+
description?: string;
|
|
5
|
+
checked: boolean;
|
|
6
|
+
onCheckedChange: (checked: boolean) => void;
|
|
7
|
+
disabled?: boolean;
|
|
8
|
+
}
|
|
9
|
+
declare function CheckboxGroupItem({ id, label, description, checked, onCheckedChange, disabled, }: CheckboxGroupItemProps): import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
export { CheckboxGroupItem };
|
|
11
|
+
//# sourceMappingURL=checkbox-group-item.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checkbox-group-item.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/web/components/ui/checkbox-group-item.tsx"],"names":[],"mappings":"AAKA,MAAM,WAAW,sBAAsB;IACrC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,OAAO,CAAC;IACjB,eAAe,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IAC5C,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,iBAAS,iBAAiB,CAAC,EACzB,EAAE,EACF,KAAK,EACL,WAAW,EACX,OAAO,EACP,eAAe,EACf,QAAQ,GACT,EAAE,sBAAsB,2CAsBxB;AAED,OAAO,EAAE,iBAAiB,EAAE,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { Checkbox } from '../ui/checkbox.js';
|
|
4
|
+
import { Label } from '../ui/label.js';
|
|
5
|
+
function CheckboxGroupItem({ id, label, description, checked, onCheckedChange, disabled, }) {
|
|
6
|
+
return (_jsxs("div", { className: "flex items-start gap-2", children: [_jsx(Checkbox, { id: id, className: "mt-0.75", checked: checked, onCheckedChange: (v) => onCheckedChange(v === true), disabled: disabled }), _jsxs("div", { className: "flex flex-col gap-0.5", children: [_jsx(Label, { htmlFor: id, className: "cursor-pointer text-sm font-medium", children: label }), description ? (_jsx(Label, { htmlFor: id, className: "text-muted-foreground cursor-pointer text-xs font-normal", children: description })) : null] })] }));
|
|
7
|
+
}
|
|
8
|
+
export { CheckboxGroupItem };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { CheckboxGroupItem } from './checkbox-group-item.js';
|
|
3
|
+
/**
|
|
4
|
+
* **CheckboxGroupItem** renders a single checkbox row with a label and optional
|
|
5
|
+
* description. It is the building block used inside `CheckboxGroup` but can
|
|
6
|
+
* also be used standalone when you need a labelled checkbox with a description.
|
|
7
|
+
*/
|
|
8
|
+
declare const meta: Meta<typeof CheckboxGroupItem>;
|
|
9
|
+
export default meta;
|
|
10
|
+
type Story = StoryObj<typeof CheckboxGroupItem>;
|
|
11
|
+
/** Unchecked item with label only. */
|
|
12
|
+
export declare const Default: Story;
|
|
13
|
+
/** Item with label and description text. */
|
|
14
|
+
export declare const WithDescription: Story;
|
|
15
|
+
/** Disabled state — both checked and unchecked. */
|
|
16
|
+
export declare const Disabled: Story;
|
|
17
|
+
//# sourceMappingURL=checkbox-group-item.stories.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checkbox-group-item.stories.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/web/components/ui/checkbox-group-item.stories.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAE1D;;;;GAIG;AACH,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,iBAAiB,CAKxC,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAEhD,sCAAsC;AACtC,eAAO,MAAM,OAAO,EAAE,KAYrB,CAAC;AAEF,4CAA4C;AAC5C,eAAO,MAAM,eAAe,EAAE,KAa7B,CAAC;AAEF,mDAAmD;AACnD,eAAO,MAAM,QAAQ,EAAE,KAqBtB,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { CheckboxGroupItem } from './checkbox-group-item.js';
|
|
4
|
+
/**
|
|
5
|
+
* **CheckboxGroupItem** renders a single checkbox row with a label and optional
|
|
6
|
+
* description. It is the building block used inside `CheckboxGroup` but can
|
|
7
|
+
* also be used standalone when you need a labelled checkbox with a description.
|
|
8
|
+
*/
|
|
9
|
+
const meta = {
|
|
10
|
+
title: 'Primitives/CheckboxGroupItem',
|
|
11
|
+
component: CheckboxGroupItem,
|
|
12
|
+
parameters: { layout: 'centered' },
|
|
13
|
+
tags: ['autodocs'],
|
|
14
|
+
};
|
|
15
|
+
export default meta;
|
|
16
|
+
/** Unchecked item with label only. */
|
|
17
|
+
export const Default = {
|
|
18
|
+
render: function Render() {
|
|
19
|
+
const [checked, setChecked] = useState(false);
|
|
20
|
+
return (_jsx(CheckboxGroupItem, { id: "demo", label: "Enable notifications", checked: checked, onCheckedChange: setChecked }));
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
/** Item with label and description text. */
|
|
24
|
+
export const WithDescription = {
|
|
25
|
+
render: function Render() {
|
|
26
|
+
const [checked, setChecked] = useState(false);
|
|
27
|
+
return (_jsx(CheckboxGroupItem, { id: "demo-desc", label: "Auto-approve PRD", description: "Automatically approve requirements and move to planning.", checked: checked, onCheckedChange: setChecked }));
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
/** Disabled state — both checked and unchecked. */
|
|
31
|
+
export const Disabled = {
|
|
32
|
+
render: () => (_jsxs("div", { className: "flex flex-col gap-4", children: [_jsx(CheckboxGroupItem, { id: "disabled-off", label: "Disabled unchecked", description: "Cannot be toggled.", checked: false, onCheckedChange: () => undefined, disabled: true }), _jsx(CheckboxGroupItem, { id: "disabled-on", label: "Disabled checked", description: "Cannot be toggled.", checked: true, onCheckedChange: () => undefined, disabled: true })] })),
|
|
33
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export interface CheckboxGroupOption {
|
|
2
|
+
id: string;
|
|
3
|
+
label: string;
|
|
4
|
+
description?: string;
|
|
5
|
+
}
|
|
6
|
+
export interface CheckboxGroupProps {
|
|
7
|
+
/** Visible group label rendered next to the parent checkbox. */
|
|
8
|
+
label: string;
|
|
9
|
+
/** Optional description rendered below the parent label. */
|
|
10
|
+
description?: string;
|
|
11
|
+
/** Accessible name for the parent checkbox (used as aria-label). */
|
|
12
|
+
parentAriaLabel?: string;
|
|
13
|
+
options: CheckboxGroupOption[];
|
|
14
|
+
/** Record mapping option id → checked state. */
|
|
15
|
+
value: Record<string, boolean>;
|
|
16
|
+
onValueChange: (value: Record<string, boolean>) => void;
|
|
17
|
+
disabled?: boolean;
|
|
18
|
+
}
|
|
19
|
+
declare function CheckboxGroup({ label, description, parentAriaLabel, options, value, onValueChange, disabled, }: CheckboxGroupProps): import("react/jsx-runtime").JSX.Element;
|
|
20
|
+
export { CheckboxGroup };
|
|
21
|
+
//# sourceMappingURL=checkbox-group.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checkbox-group.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/web/components/ui/checkbox-group.tsx"],"names":[],"mappings":"AAMA,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,kBAAkB;IACjC,gEAAgE;IAChE,KAAK,EAAE,MAAM,CAAC;IACd,4DAA4D;IAC5D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oEAAoE;IACpE,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,OAAO,EAAE,mBAAmB,EAAE,CAAC;IAC/B,gDAAgD;IAChD,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IACxD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,iBAAS,aAAa,CAAC,EACrB,KAAK,EACL,WAAW,EACX,eAAe,EACf,OAAO,EACP,KAAK,EACL,aAAa,EACb,QAAQ,GACT,EAAE,kBAAkB,2CA+DpB;AAED,OAAO,EAAE,aAAa,EAAE,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { Checkbox } from '../ui/checkbox.js';
|
|
4
|
+
import { Label } from '../ui/label.js';
|
|
5
|
+
import { CheckboxGroupItem } from '../ui/checkbox-group-item.js';
|
|
6
|
+
function CheckboxGroup({ label, description, parentAriaLabel, options, value, onValueChange, disabled, }) {
|
|
7
|
+
const selectedCount = options.filter((o) => value[o.id]).length;
|
|
8
|
+
const parentChecked = selectedCount === options.length;
|
|
9
|
+
const parentIndeterminate = selectedCount > 0 && !parentChecked;
|
|
10
|
+
const handleParentToggle = () => {
|
|
11
|
+
const target = selectedCount < options.length;
|
|
12
|
+
const next = {};
|
|
13
|
+
for (const o of options) {
|
|
14
|
+
next[o.id] = target;
|
|
15
|
+
}
|
|
16
|
+
onValueChange(next);
|
|
17
|
+
};
|
|
18
|
+
const handleItemChange = (id, checked) => {
|
|
19
|
+
onValueChange({ ...value, [id]: checked });
|
|
20
|
+
};
|
|
21
|
+
const parentId = `${label.toLowerCase().replace(/\s+/g, '-')}-group`;
|
|
22
|
+
return (_jsxs("div", { className: "flex flex-col gap-3", children: [_jsxs("div", { className: "flex items-start gap-2", children: [_jsx(Checkbox, { id: parentId, className: "mt-0.75", checked: parentIndeterminate ? 'indeterminate' : parentChecked, onCheckedChange: handleParentToggle, disabled: disabled, "aria-label": parentAriaLabel ?? `${label} select all` }), _jsxs("div", { className: "flex flex-col gap-0.5", children: [_jsx(Label, { htmlFor: parentId, className: "cursor-pointer text-sm font-medium", children: label }), description ? (_jsx(Label, { htmlFor: parentId, className: "text-muted-foreground cursor-pointer text-xs font-normal", children: description })) : null] })] }), _jsx("div", { className: "flex flex-col gap-3 pl-6", children: options.map((option) => (_jsx(CheckboxGroupItem, { id: option.id, label: option.label, description: option.description, checked: value[option.id] ?? false, onCheckedChange: (checked) => handleItemChange(option.id, checked), disabled: disabled }, option.id))) })] }));
|
|
23
|
+
}
|
|
24
|
+
export { CheckboxGroup };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { CheckboxGroup } from './checkbox-group.js';
|
|
3
|
+
/**
|
|
4
|
+
* **CheckboxGroup** is a tri-state parent checkbox with child items.
|
|
5
|
+
*
|
|
6
|
+
* - **Parent unchecked**: no children selected. Click → selects all.
|
|
7
|
+
* - **Parent checked**: all children selected. Click → deselects all.
|
|
8
|
+
* - **Parent indeterminate** (dash): some children selected. Click → selects all.
|
|
9
|
+
*
|
|
10
|
+
* Built on `Checkbox` and `CheckboxGroupItem`.
|
|
11
|
+
*/
|
|
12
|
+
declare const meta: Meta<typeof CheckboxGroup>;
|
|
13
|
+
export default meta;
|
|
14
|
+
type Story = StoryObj<typeof CheckboxGroup>;
|
|
15
|
+
/** All unchecked — parent shows empty checkbox. */
|
|
16
|
+
export declare const AllUnchecked: Story;
|
|
17
|
+
/** All checked — parent shows checkmark. */
|
|
18
|
+
export declare const AllChecked: Story;
|
|
19
|
+
/** Partial selection — parent shows indeterminate dash. */
|
|
20
|
+
export declare const Indeterminate: Story;
|
|
21
|
+
/** Disabled state — all controls non-interactive. */
|
|
22
|
+
export declare const Disabled: Story;
|
|
23
|
+
//# sourceMappingURL=checkbox-group.stories.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checkbox-group.stories.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/web/components/ui/checkbox-group.stories.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAQjD;;;;;;;;GAQG;AACH,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,aAAa,CAKpC,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,aAAa,CAAC,CAAC;AAE5C,mDAAmD;AACnD,eAAO,MAAM,YAAY,EAAE,KAkB1B,CAAC;AAEF,4CAA4C;AAC5C,eAAO,MAAM,UAAU,EAAE,KAkBxB,CAAC;AAEF,2DAA2D;AAC3D,eAAO,MAAM,aAAa,EAAE,KAkB3B,CAAC;AAEF,qDAAqD;AACrD,eAAO,MAAM,QAAQ,EAAE,KAWtB,CAAC"}
|