frontend/src/components/Plan/components/HeaderSection/Actions/ACTIONS.md
This document describes all available actions in the Plan Header section, including visibility rules, permissions, and disabled states.
The action system uses a Registry Pattern for maintainability and type safety.
Actions/
├── registry/ # Action Registry (source of truth)
│ ├── types.ts # ActionContext, ActionDefinition interfaces
│ ├── context.ts # buildActionContext() - context builder
│ ├── useActionRegistry.ts # Main composable
│ ├── actions/
│ │ ├── plan.ts # PLAN_CLOSE, PLAN_REOPEN
│ │ ├── issue.ts # ISSUE_CREATE, ISSUE_REVIEW, ISSUE_STATUS_*
│ │ └── rollout.ts # ROLLOUT_CREATE, ROLLOUT_START, ROLLOUT_CANCEL, EXPORT_DOWNLOAD
│ └── components/
│ ├── ActionButton.vue # Single action button
│ ├── ActionDropdown.vue # Secondary actions dropdown
│ └── IssueReviewButton.vue # Review popover with approve/reject/comment
└── Actions.vue # Main orchestrator
ActionContext: Single reactive object containing all state needed for action decisions:
hasDeferredRollout: Plans where rollout is created on-demand (export, create database). For these plans:
ActionDefinition: Declarative action with pure functions:
interface ActionDefinition {
id: UnifiedActionType;
label: (ctx: ActionContext) => string;
buttonType: "primary" | "success" | "default";
category: ActionCategory | ((ctx: ActionContext) => ActionCategory); // Can be dynamic
priority: number; // Lower = higher priority
isVisible: (ctx: ActionContext) => boolean;
isDisabled: (ctx: ActionContext) => boolean;
disabledReason: (ctx: ActionContext) => string | undefined;
executeType: ExecuteType;
}
ISSUE_CREATE (Primary, Priority: 5)Label: "Ready for review"
Description: Creates an issue from the plan and initiates the approval workflow.
Visibility:
plan.issue === "")plan.rollout === "")bb.issues.create permissionDisabled When:
project.enforceSqlReview)PLAN_CLOSE (Secondary, Priority: 100)Label: "Close"
Description: Closes (archives) the plan.
Visibility:
bb.plans.update permissionPLAN_REOPEN (Primary, Priority: 10)Label: "Reopen"
Description: Reopens a closed (archived) plan.
Visibility:
bb.plans.update permissionISSUE_REVIEW (Primary, Priority: 30)Label: "Review"
Description: Opens the unified review popover for approve/reject/comment.
Visibility:
ISSUE_STATUS_CLOSE (Secondary, Priority: 90)Label: "Close"
Description: Closes the issue without resolving it (CANCELED).
Visibility:
bb.issues.update permissionISSUE_STATUS_REOPEN (Primary, Priority: 20)Label: "Reopen"
Description: Reopens a canceled issue.
Visibility:
bb.issues.update permissionROLLOUT_CREATE (Primary/Secondary, Priority: 55)Label: "Create Rollout"
Description: Creates a rollout from the issue. Shows as primary action when ready, moves to dropdown when conditions aren't met.
Visibility:
bb.rollouts.create permissionrequireIssueApproval=true AND issue not APPROVED/SKIPPED → hiddenrequirePlanCheckNoError=true AND plan checks failed → hiddenCategory Logic:
Warning Panel (shown when clicking from dropdown):
requireIssueApproval=false AND approval not APPROVED/SKIPPED → shows approval flow sectionrequirePlanCheckNoError=false AND plan checks failed → shows plan check statusWhen warnings exist, user must check "Bypass stage requirements" checkbox to proceed.
ROLLOUT_START (Primary, Priority: 60)Label:
Description: Starts or retries tasks in the rollout. For deferred rollout plans (export/create database), this action creates the rollout and runs all tasks in one step.
Visibility: For deferred rollout plans (export/create database):
bb.taskRuns.create permissionFor regular plans:
bb.taskRuns.create permission OR is creator (for exports)ROLLOUT_CANCEL (Secondary, Priority: 80)Label: "Cancel"
Description: Cancels running or pending tasks.
Visibility:
EXPORT_DOWNLOAD (Primary, Priority: 0)Label: "Download"
Description: Downloads completed export archive.
Visibility:
The ROLLOUT_CREATE button visibility and category depend on project settings and current state:
| Condition | Result |
|---|---|
requireIssueApproval=true + not approved | Hidden |
requirePlanCheckNoError=true + checks failed | Hidden |
requireIssueApproval=false + not approved | Secondary (dropdown) with warning |
requirePlanCheckNoError=false + checks failed | Secondary (dropdown) with warning |
| Plan checks running | Secondary (dropdown) with warning |
| All conditions met | Primary (main button) |
Task execution (RUN/SKIP/CANCEL) always shows warnings for approval and plan check issues, never errors. Users can bypass these warnings to proceed.
All actions are disabled when:
editorState.isEditing === true)Actions are sorted by priority (lower number = higher priority). The first visible primary action is shown as the main button.
| Priority | Action | Category |
|---|---|---|
| 0 | EXPORT_DOWNLOAD | primary |
| 5 | ISSUE_CREATE | primary |
| 10 | PLAN_REOPEN | primary |
| 20 | ISSUE_STATUS_REOPEN | primary |
| 30 | ISSUE_REVIEW | primary |
| 55 | ROLLOUT_CREATE | primary |
| 60 | ROLLOUT_START | primary |
| 80 | ROLLOUT_CANCEL | secondary |
| 90 | ISSUE_STATUS_CLOSE | secondary |
| 100 | PLAN_CLOSE | secondary |
bb.plans.update: Close or reopen plansbb.issues.create: Create issues from plansbb.issues.update: Close or reopen issuesbb.rollouts.create: Create rolloutsbb.taskRuns.create: Run rollout tasksimport { useActionRegistry } from "./registry";
const {
context, // Reactive ActionContext
primaryAction, // First visible primary action
secondaryActions, // All visible secondary actions
isActionDisabled, // Check if action is disabled
getDisabledReason, // Get disabled tooltip
executeAction, // Execute action by ID
} = useActionRegistry();
registry/actions/*.ts):export const MY_NEW_ACTION: ActionDefinition = {
id: "MY_NEW_ACTION",
label: () => t("my-action.label"),
buttonType: "primary",
category: "primary",
priority: 45,
isVisible: (ctx) => /* visibility logic */,
isDisabled: (ctx) => /* disabled logic */,
disabledReason: (ctx) => /* reason or undefined */,
executeType: "immediate",
};
registry/types.tsActions.vue if needed