Skip to content

Commit 6795829

Browse files
authored
🤖 feat: promote plan primary actions (#2055)
Summary - Right-align the plan's primary next-step actions (Implement + Orchestrator) as prominent icon+text buttons. - Keep utility actions (Copy/Share/Start Here/Show Text/etc.) as the existing left-side icon buttons. Validation - make lint - make typecheck --- _Generated with `mux` • Model: `openai:gpt-5.2` • Thinking: `xhigh` • Cost: `$0.45`_ <!-- mux-attribution: model=openai:gpt-5.2 thinking=xhigh costs=0.45 -->
1 parent a28b996 commit 6795829

1 file changed

Lines changed: 79 additions & 24 deletions

File tree

src/browser/components/tools/ProposePlanToolCall.tsx

Lines changed: 79 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
import { useToolExpansion, getStatusDisplay, type ToolStatus } from "./shared/toolUtils";
1717
import { MarkdownRenderer } from "../Messages/MarkdownRenderer";
1818
import { Button } from "../ui/button";
19+
import { Tooltip, TooltipTrigger, TooltipContent } from "../ui/tooltip";
1920
import { IconActionButton, type ButtonConfig } from "../Messages/MessageWindow";
2021
import { formatKeybind, KEYBINDS } from "@/browser/utils/ui/keybinds";
2122
import { useStartHere } from "@/browser/hooks/useStartHere";
@@ -508,37 +509,43 @@ export const ProposePlanToolCall: React.FC<ProposePlanToolCallProps> = (props) =
508509
}
509510
: null;
510511

511-
// Start Here button: only for tool calls, not ephemeral previews
512-
if (!isEphemeralPreview && workspaceId) {
513-
actionButtons.push({
514-
label: buttonLabel,
515-
onClick: openModal,
516-
disabled: startHereDisabled,
517-
icon: <ListStart />,
518-
tooltip: "Replace all chat history with this plan",
519-
});
512+
const shouldShowPrimaryActions = Boolean(
513+
status === "completed" && !errorMessage && isLatest && !isEphemeralPreview && workspaceId
514+
);
520515

521-
if (status === "completed" && !errorMessage && isLatest) {
522-
actionButtons.push({
516+
const implementButton: ButtonConfig | null = shouldShowPrimaryActions
517+
? {
523518
label: "Implement",
524519
onClick: () => void handleImplement(),
525520
disabled: !api || isImplementing || isStartingOrchestrator,
526-
icon: <Play />,
521+
icon: <Play className="size-4" />,
527522
tooltip: implementReplacesChatHistory
528523
? "Replace chat history with this plan, switch to Exec, and start implementing"
529524
: "Switch to Exec and start implementing",
530-
});
525+
}
526+
: null;
531527

532-
actionButtons.push({
528+
const orchestratorButton: ButtonConfig | null = shouldShowPrimaryActions
529+
? {
533530
label: "Start Orchestrator",
534531
onClick: () => void handleStartOrchestrator(),
535532
disabled: !api || isStartingOrchestrator || isImplementing,
536-
icon: <Workflow />,
533+
icon: <Workflow className="size-4" />,
537534
tooltip: implementReplacesChatHistory
538535
? "Replace chat history with this plan, switch to Orchestrator, and start delegating"
539536
: "Switch to Orchestrator and start delegating",
540-
});
541-
}
537+
}
538+
: null;
539+
540+
// Start Here button: only for tool calls, not ephemeral previews
541+
if (!isEphemeralPreview && workspaceId) {
542+
actionButtons.push({
543+
label: buttonLabel,
544+
onClick: openModal,
545+
disabled: startHereDisabled,
546+
icon: <ListStart />,
547+
tooltip: "Replace all chat history with this plan",
548+
});
542549
}
543550

544551
// Show raw toggle
@@ -609,13 +616,61 @@ export const ProposePlanToolCall: React.FC<ProposePlanToolCallProps> = (props) =
609616

610617
{/* Actions row at the bottom (matching MessageWindow style) */}
611618
<div className="mt-3 flex items-center gap-0.5">
612-
{actionButtons.map((button, index) => (
613-
<IconActionButton key={index} button={button} />
614-
))}
615-
{/* Edit button rendered with ref for error popover positioning */}
616-
{editButton && (
617-
<div ref={editButtonRef}>
618-
<IconActionButton button={editButton} />
619+
<div className="flex min-w-0 flex-1 items-center gap-0.5">
620+
{actionButtons.map((button, index) => (
621+
<IconActionButton key={index} button={button} />
622+
))}
623+
{/* Edit button rendered with ref for error popover positioning */}
624+
{editButton && (
625+
<div ref={editButtonRef}>
626+
<IconActionButton button={editButton} />
627+
</div>
628+
)}
629+
</div>
630+
631+
{(implementButton ?? orchestratorButton) && (
632+
<div className="ml-auto flex items-center gap-1">
633+
{implementButton && (
634+
<Tooltip>
635+
<TooltipTrigger asChild>
636+
<Button
637+
type="button"
638+
variant="outline"
639+
size="sm"
640+
className="h-7 gap-1"
641+
onClick={implementButton.onClick}
642+
disabled={implementButton.disabled}
643+
>
644+
{implementButton.icon}
645+
<span className="leading-none">{implementButton.label}</span>
646+
</Button>
647+
</TooltipTrigger>
648+
<TooltipContent align="center">
649+
{implementButton.tooltip ?? implementButton.label}
650+
</TooltipContent>
651+
</Tooltip>
652+
)}
653+
654+
{orchestratorButton && (
655+
<Tooltip>
656+
<TooltipTrigger asChild>
657+
<Button
658+
type="button"
659+
variant="outline"
660+
size="sm"
661+
className="h-7 gap-1"
662+
onClick={orchestratorButton.onClick}
663+
disabled={orchestratorButton.disabled}
664+
>
665+
{orchestratorButton.icon}
666+
<span className="leading-none">{orchestratorButton.label}</span>
667+
</Button>
668+
</TooltipTrigger>
669+
<TooltipContent align="center">
670+
{orchestratorButton.tooltip ?? orchestratorButton.label}
671+
</TooltipContent>
672+
</Tooltip>
673+
)}
619674
</div>
620675
)}
621676
</div>

0 commit comments

Comments
 (0)