Skip to content

Commit fe3d905

Browse files
committed
feat: Make mode selection a select
1 parent f7f776a commit fe3d905

File tree

6 files changed

+113
-48
lines changed

6 files changed

+113
-48
lines changed

apps/twig/src/renderer/features/message-editor/components/MessageEditor.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ interface MessageEditorProps {
2626
onAttachFiles?: (files: File[]) => void;
2727
autoFocus?: boolean;
2828
currentMode?: ExecutionMode;
29-
onModeChange?: () => void;
29+
onModeChange?: (mode: ExecutionMode) => void;
3030
}
3131

3232
export const MessageEditor = forwardRef<EditorHandle, MessageEditorProps>(
@@ -206,7 +206,7 @@ export const MessageEditor = forwardRef<EditorHandle, MessageEditorProps>(
206206
</Flex>
207207
</Flex>
208208
{onModeChange && currentMode && (
209-
<ModeIndicatorInput mode={currentMode} />
209+
<ModeIndicatorInput mode={currentMode} onModeChange={onModeChange} />
210210
)}
211211
</Flex>
212212
);
Lines changed: 94 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
import type { ExecutionMode } from "@features/sessions/stores/sessionStore";
22
import { LockOpen, Pause, Pencil, ShieldCheck } from "@phosphor-icons/react";
3-
import { Flex, Text } from "@radix-ui/themes";
3+
import { Flex, Select, Text } from "@radix-ui/themes";
4+
import { EXECUTION_MODES } from "@shared/constants";
45

56
interface ModeIndicatorInputProps {
67
mode: ExecutionMode;
8+
onModeChange: (mode: ExecutionMode) => void;
9+
disabled?: boolean;
710
}
811

912
const modeConfig: Record<
@@ -16,55 +19,115 @@ const modeConfig: Record<
1619
> = {
1720
plan: {
1821
label: "plan mode on",
19-
icon: <Pause size={12} weight="bold" />,
22+
icon: <Pause size={12} weight="bold" color="var(--amber-11)" />,
2023
colorVar: "var(--amber-11)",
2124
},
2225
default: {
2326
label: "default mode",
24-
icon: <Pencil size={12} />,
27+
icon: <Pencil size={12} color="var(--gray-11)" />,
2528
colorVar: "var(--gray-11)",
2629
},
2730
acceptEdits: {
2831
label: "auto-accept edits",
29-
icon: <ShieldCheck size={12} weight="fill" />,
32+
icon: <ShieldCheck size={12} weight="fill" color="var(--green-11)" />,
3033
colorVar: "var(--green-11)",
3134
},
3235
bypassPermissions: {
3336
label: "bypass permissions",
34-
icon: <LockOpen size={12} weight="bold" />,
37+
icon: <LockOpen size={12} weight="bold" color="var(--red-11)" />,
3538
colorVar: "var(--red-11)",
3639
},
3740
};
3841

39-
export function ModeIndicatorInput({ mode }: ModeIndicatorInputProps) {
42+
export function ModeIndicatorInput({
43+
mode,
44+
onModeChange,
45+
disabled,
46+
}: ModeIndicatorInputProps) {
4047
const config = modeConfig[mode];
4148

4249
return (
43-
<Flex align="center" justify="between" py="1">
44-
<Flex align="center" gap="1">
45-
<Text
46-
size="1"
47-
style={{
48-
color: config.colorVar,
49-
fontFamily: "monospace",
50-
display: "flex",
51-
alignItems: "center",
52-
gap: "4px",
53-
}}
54-
>
50+
<Select.Root
51+
value={mode}
52+
onValueChange={onModeChange}
53+
disabled={disabled}
54+
size="1"
55+
>
56+
<Select.Trigger
57+
className="w-fit"
58+
onClick={(e) => {
59+
e.stopPropagation();
60+
}}
61+
>
62+
<Flex align="center" gap="1">
5563
{config.icon}
56-
{config.label}
57-
</Text>
58-
<Text
59-
size="1"
60-
style={{
61-
color: "var(--gray-9)",
62-
fontFamily: "monospace",
63-
}}
64-
>
65-
(shift+tab to cycle)
66-
</Text>
67-
</Flex>
68-
</Flex>
64+
<Text
65+
size="1"
66+
style={{
67+
color: config.colorVar,
68+
fontFamily: "monospace",
69+
}}
70+
>
71+
{config.label}
72+
</Text>
73+
<Text
74+
size="1"
75+
style={{
76+
color: "var(--gray-9)",
77+
fontFamily: "monospace",
78+
}}
79+
>
80+
(shift+tab to cycle)
81+
</Text>
82+
</Flex>
83+
</Select.Trigger>
84+
<Select.Content>
85+
{EXECUTION_MODES.map((modeOption) => {
86+
const optionConfig = modeConfig[modeOption];
87+
const hoverBgClass =
88+
modeOption === "plan"
89+
? "hover:!bg-[var(--amber-11)]"
90+
: modeOption === "default"
91+
? "hover:!bg-[var(--gray-11)]"
92+
: modeOption === "acceptEdits"
93+
? "hover:!bg-[var(--green-11)]"
94+
: "hover:!bg-[var(--red-11)]";
95+
return (
96+
<Select.Item
97+
key={modeOption}
98+
value={modeOption}
99+
className={`group transition-colors ${hoverBgClass}`}
100+
>
101+
<Flex
102+
align="center"
103+
gap="1"
104+
className="group-hover:!text-[black] [&_svg]:group-hover:!text-[black] [&_svg]:group-hover:!fill-[black] [&_svg_path]:group-hover:!fill-[black] [&_svg_path]:group-hover:!stroke-[black]"
105+
style={{
106+
color: optionConfig.colorVar,
107+
fontFamily: "monospace",
108+
}}
109+
>
110+
<span className="group-hover:[&_svg]:!text-[black] group-hover:[&_svg]:!fill-[black] group-hover:[&_svg_path]:!fill-[black] group-hover:[&_svg_path]:!stroke-[black]">
111+
{optionConfig.icon}
112+
</span>
113+
<Text size="1" className="group-hover:!text-[black]">
114+
{optionConfig.label}
115+
</Text>
116+
</Flex>
117+
</Select.Item>
118+
);
119+
})}
120+
</Select.Content>
121+
<style>{`
122+
.group:hover svg {
123+
color: black !important;
124+
fill: black !important;
125+
}
126+
.group:hover svg path {
127+
fill: black !important;
128+
stroke: black !important;
129+
}
130+
`}</style>
131+
</Select.Root>
69132
);
70133
}

apps/twig/src/renderer/features/sessions/components/SessionView.tsx

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
import type { Plan } from "@features/sessions/types";
1313
import { Warning } from "@phosphor-icons/react";
1414
import { Box, Button, ContextMenu, Flex, Text } from "@radix-ui/themes";
15+
import { EXECUTION_MODES } from "@shared/constants";
1516
import {
1617
type AcpMessage,
1718
isJsonRpcNotification,
@@ -29,13 +30,6 @@ import { InlinePermissionSelector } from "./InlinePermissionSelector";
2930
import { PlanStatusBar } from "./PlanStatusBar";
3031
import { RawLogsView } from "./raw-logs/RawLogsView";
3132

32-
const EXECUTION_MODES: ExecutionMode[] = [
33-
"plan",
34-
"default",
35-
"acceptEdits",
36-
"bypassPermissions",
37-
];
38-
3933
function cycleMode(current: ExecutionMode): ExecutionMode {
4034
const currentIndex = EXECUTION_MODES.indexOf(current);
4135
const nextIndex = (currentIndex + 1) % EXECUTION_MODES.length;

apps/twig/src/renderer/features/task-detail/components/TaskInput.tsx

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { useSettingsStore } from "@features/settings/stores/settingsStore";
66
import { useRepositoryIntegration } from "@hooks/useIntegrations";
77
import { Flex } from "@radix-ui/themes";
88
import { useRegisteredFoldersStore } from "@renderer/stores/registeredFoldersStore";
9+
import { EXECUTION_MODES } from "@shared/constants";
910
import { useNavigationStore } from "@stores/navigationStore";
1011
import { useTaskDirectoryStore } from "@stores/taskDirectoryStore";
1112
import { useCallback, useEffect, useRef, useState } from "react";
@@ -14,13 +15,6 @@ import { SuggestedTasks } from "./SuggestedTasks";
1415
import { TaskInputEditor } from "./TaskInputEditor";
1516
import { type WorkspaceMode, WorkspaceModeSelect } from "./WorkspaceModeSelect";
1617

17-
const EXECUTION_MODES: ExecutionMode[] = [
18-
"plan",
19-
"default",
20-
"acceptEdits",
21-
"bypassPermissions",
22-
];
23-
2418
function cycleMode(current: ExecutionMode): ExecutionMode {
2519
const currentIndex = EXECUTION_MODES.indexOf(current);
2620
const nextIndex = (currentIndex + 1) % EXECUTION_MODES.length;

apps/twig/src/renderer/features/task-detail/components/TaskInputEditor.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,12 @@ export const TaskInputEditor = forwardRef<
233233
</Flex>
234234
</Flex>
235235
</Flex>
236-
{!isCloudMode && <ModeIndicatorInput mode={executionMode} />}
236+
{!isCloudMode && (
237+
<ModeIndicatorInput
238+
mode={executionMode}
239+
onModeChange={onModeChange}
240+
/>
241+
)}
237242
</>
238243
);
239244
},

apps/twig/src/shared/constants.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import type { ExecutionMode } from "@/main/services/agent/schemas";
2+
13
/**
24
* Branch naming conventions.
35
* - Reading: Accept all prefixes for backwards compatibility
@@ -21,3 +23,10 @@ export function isTwigBranch(branchName: string): boolean {
2123
export const DATA_DIR = ".twig";
2224
export const WORKSPACES_DIR = ".twig/workspaces";
2325
export const LEGACY_DATA_DIRS = [".array"];
26+
27+
export const EXECUTION_MODES: ExecutionMode[] = [
28+
"default",
29+
"acceptEdits",
30+
"plan",
31+
"bypassPermissions",
32+
];

0 commit comments

Comments
 (0)