feat: implement pipeline step exclusion functionality

- Added support for excluding specific pipeline steps in feature management, allowing users to skip certain steps during execution.
- Introduced a new `PipelineExclusionControls` component for managing exclusions in the UI.
- Updated relevant dialogs and components to handle excluded pipeline steps, including `AddFeatureDialog`, `EditFeatureDialog`, and `MassEditDialog`.
- Enhanced the `getNextStatus` method in `PipelineService` to account for excluded steps when determining the next status in the pipeline flow.
- Updated tests to cover scenarios involving excluded pipeline steps.
This commit is contained in:
Shirone
2026-01-21 08:34:55 +01:00
parent 2ab78dd590
commit a73a57b9a4
17 changed files with 783 additions and 22 deletions

View File

@@ -45,6 +45,7 @@ import {
AncestorContextSection,
EnhanceWithAI,
EnhancementHistoryButton,
PipelineExclusionControls,
type BaseHistoryEntry,
} from '../shared';
import type { WorkMode } from '../shared';
@@ -101,6 +102,7 @@ type FeatureData = {
requirePlanApproval: boolean;
dependencies?: string[];
childDependencies?: string[]; // Feature IDs that should depend on this feature
excludedPipelineSteps?: string[]; // Pipeline step IDs to skip for this feature
workMode: WorkMode;
};
@@ -118,6 +120,10 @@ interface AddFeatureDialogProps {
isMaximized: boolean;
parentFeature?: Feature | null;
allFeatures?: Feature[];
/**
* Path to the current project for loading pipeline config.
*/
projectPath?: string;
/**
* When a non-main worktree is selected in the board header, this will be set to that worktree's branch.
* When set, the dialog will default to 'custom' work mode with this branch pre-filled.
@@ -151,6 +157,7 @@ export function AddFeatureDialog({
isMaximized,
parentFeature = null,
allFeatures = [],
projectPath,
selectedNonMainWorktreeBranch,
forceCurrentBranchMode,
}: AddFeatureDialogProps) {
@@ -194,6 +201,9 @@ export function AddFeatureDialog({
const [parentDependencies, setParentDependencies] = useState<string[]>([]);
const [childDependencies, setChildDependencies] = useState<string[]>([]);
// Pipeline exclusion state
const [excludedPipelineSteps, setExcludedPipelineSteps] = useState<string[]>([]);
// Get defaults from store
const { defaultPlanningMode, defaultRequirePlanApproval, useWorktrees, defaultFeatureModel } =
useAppStore();
@@ -234,6 +244,9 @@ export function AddFeatureDialog({
// Reset dependency selections
setParentDependencies([]);
setChildDependencies([]);
// Reset pipeline exclusions (all pipelines enabled by default)
setExcludedPipelineSteps([]);
}
}, [
open,
@@ -328,6 +341,7 @@ export function AddFeatureDialog({
requirePlanApproval,
dependencies: finalDependencies,
childDependencies: childDependencies.length > 0 ? childDependencies : undefined,
excludedPipelineSteps: excludedPipelineSteps.length > 0 ? excludedPipelineSteps : undefined,
workMode,
};
};
@@ -354,6 +368,7 @@ export function AddFeatureDialog({
setDescriptionHistory([]);
setParentDependencies([]);
setChildDependencies([]);
setExcludedPipelineSteps([]);
onOpenChange(false);
};
@@ -696,6 +711,16 @@ export function AddFeatureDialog({
</div>
</div>
)}
{/* Pipeline Exclusion Controls */}
<div className="pt-2">
<PipelineExclusionControls
projectPath={projectPath}
excludedPipelineSteps={excludedPipelineSteps}
onExcludedStepsChange={setExcludedPipelineSteps}
testIdPrefix="add-feature-pipeline"
/>
</div>
</div>
</div>