11/* Copyright 2024 Marimo. All rights reserved. */
22
3- import { useAtomValue , useSetAtom } from "jotai" ;
4- import { WrenchIcon , ZapIcon , ZapOffIcon } from "lucide-react" ;
3+ import { useAtomValue , useSetAtom , useStore } from "jotai" ;
4+ import { ChevronDownIcon , SparklesIcon , WrenchIcon } from "lucide-react" ;
55import { Button } from "@/components/ui/button" ;
6- import { Switch } from "@/components/ui/switch" ;
6+ import {
7+ DropdownMenu ,
8+ DropdownMenuContent ,
9+ DropdownMenuItem ,
10+ DropdownMenuTrigger ,
11+ } from "@/components/ui/dropdown-menu" ;
712import { Tooltip } from "@/components/ui/tooltip" ;
813import { aiCompletionCellAtom } from "@/core/ai/state" ;
914import { notebookAtom , useCellActions } from "@/core/cells/cells" ;
1015import type { CellId } from "@/core/cells/ids" ;
1116import { aiEnabledAtom } from "@/core/config/config" ;
1217import { getAutoFixes } from "@/core/errors/errors" ;
1318import type { MarimoError } from "@/core/kernel/messages" ;
14- import { store } from "@/core/state/jotai" ;
1519import { cn } from "@/utils/cn" ;
16- import { useInstantAIFix } from "./instant- fix" ;
20+ import { useFixMode } from "./fix-mode " ;
1721
1822export const AutoFixButton = ( {
1923 errors,
@@ -24,7 +28,7 @@ export const AutoFixButton = ({
2428 cellId : CellId ;
2529 className ?: string ;
2630} ) => {
27- const { instantAIFix , setInstantAIFix } = useInstantAIFix ( ) ;
31+ const store = useStore ( ) ;
2832 const { createNewCell } = useCellActions ( ) ;
2933 const aiEnabled = useAtomValue ( aiEnabledAtom ) ;
3034 const autoFixes = errors . flatMap ( ( error ) =>
@@ -40,7 +44,7 @@ export const AutoFixButton = ({
4044 // multiple fixes.
4145 const firstFix = autoFixes [ 0 ] ;
4246
43- const handleFix = ( ) => {
47+ const handleFix = ( triggerFix : boolean ) => {
4448 const editorView =
4549 store . get ( notebookAtom ) . cellHandles [ cellId ] . current ?. editorView ;
4650 firstFix . onFix ( {
@@ -56,49 +60,118 @@ export const AutoFixButton = ({
5660 cellId : cellId ,
5761 aiFix : {
5862 setAiCompletionCell,
59- instantFix : instantAIFix ,
63+ triggerFix ,
6064 } ,
6165 } ) ;
6266 // Focus the editor
6367 editorView ?. focus ( ) ;
6468 } ;
6569
6670 return (
67- < div className = { cn ( "flex gap-2 my-2 items-center" , className ) } >
68- < Tooltip content = { firstFix . description } align = "start" >
71+ < div className = { cn ( "my-2" , className ) } >
72+ { firstFix . fixType === "ai" ? (
73+ < AIFixButton
74+ tooltip = { firstFix . description }
75+ openPrompt = { ( ) => handleFix ( false ) }
76+ applyAutofix = { ( ) => handleFix ( true ) }
77+ />
78+ ) : (
79+ < Tooltip content = { firstFix . description } align = "start" >
80+ < Button
81+ size = "xs"
82+ variant = "outline"
83+ className = "font-normal"
84+ onClick = { ( ) => handleFix ( false ) }
85+ >
86+ < WrenchIcon className = "h-3 w-3 mr-2" />
87+ { firstFix . title }
88+ </ Button >
89+ </ Tooltip >
90+ ) }
91+ </ div >
92+ ) ;
93+ } ;
94+
95+ const PromptIcon = SparklesIcon ;
96+ const AutofixIcon = WrenchIcon ;
97+
98+ const PromptTitle = "Suggest a prompt" ;
99+ const AutofixTitle = "Fix with AI" ;
100+
101+ export const AIFixButton = ( {
102+ tooltip,
103+ openPrompt,
104+ applyAutofix,
105+ } : {
106+ tooltip : string ;
107+ openPrompt : ( ) => void ;
108+ applyAutofix : ( ) => void ;
109+ } ) => {
110+ const { fixMode, setFixMode } = useFixMode ( ) ;
111+
112+ return (
113+ < div className = "flex" >
114+ < Tooltip content = { tooltip } align = "start" >
69115 < Button
70116 size = "xs"
71117 variant = "outline"
72- className = "font-normal"
73- onClick = { handleFix }
118+ className = "font-normal rounded-r-none border-r-0 "
119+ onClick = { fixMode === "prompt" ? openPrompt : applyAutofix }
74120 >
75- < WrenchIcon className = "h-3 w-3 mr-2" />
76- { firstFix . title }
121+ { fixMode === "prompt" ? (
122+ < PromptIcon className = "h-3 w-3 mr-2 mb-0.5" />
123+ ) : (
124+ < AutofixIcon className = "h-3 w-3 mr-2 mb-0.5" />
125+ ) }
126+ { fixMode === "prompt" ? PromptTitle : AutofixTitle }
77127 </ Button >
78128 </ Tooltip >
79-
80- { firstFix . fixType === "ai" && (
81- < div className = "flex items-center gap-2" >
82- < Switch
83- checked = { instantAIFix }
84- onCheckedChange = { ( ) => setInstantAIFix ( ! instantAIFix ) }
85- size = "sm"
86- className = "h-4 w-8"
87- title = "Toggle instant AI fix mode"
88- />
89- < Tooltip
90- content = {
91- instantAIFix ? "Instant fix enabled" : "Instant fix disabled"
92- }
129+ < DropdownMenu >
130+ < DropdownMenuTrigger asChild = { true } >
131+ < Button
132+ size = "xs"
133+ variant = "outline"
134+ className = "rounded-l-none px-2"
135+ aria-label = "Fix options"
93136 >
94- { instantAIFix ? (
95- < ZapIcon className = "h-3 w-3 text-amber-500" />
96- ) : (
97- < ZapOffIcon className = "h-3 w-3 text-muted-foreground" />
98- ) }
99- </ Tooltip >
100- </ div >
101- ) }
137+ < ChevronDownIcon className = "h-3 w-3" />
138+ </ Button >
139+ </ DropdownMenuTrigger >
140+ < DropdownMenuContent align = "end" className = "w-56" >
141+ < DropdownMenuItem
142+ className = "flex items-center gap-2"
143+ onClick = { ( ) => {
144+ setFixMode ( fixMode === "prompt" ? "autofix" : "prompt" ) ;
145+ } }
146+ >
147+ < AiModeItem mode = { fixMode === "prompt" ? "autofix" : "prompt" } />
148+ </ DropdownMenuItem >
149+ </ DropdownMenuContent >
150+ </ DropdownMenu >
151+ </ div >
152+ ) ;
153+ } ;
154+
155+ const AiModeItem = ( { mode } : { mode : "prompt" | "autofix" } ) => {
156+ const icon =
157+ mode === "prompt" ? (
158+ < PromptIcon className = "h-4 w-4" />
159+ ) : (
160+ < AutofixIcon className = "h-4 w-4" />
161+ ) ;
162+ const title = mode === "prompt" ? PromptTitle : AutofixTitle ;
163+ const description =
164+ mode === "prompt"
165+ ? "Edit the prompt before applying"
166+ : "Apply AI fixes automatically" ;
167+
168+ return (
169+ < div className = "flex items-center gap-2" >
170+ { icon }
171+ < div className = "flex flex-col" >
172+ < span className = "font-medium" > { title } </ span >
173+ < span className = "text-xs text-muted-foreground" > { description } </ span >
174+ </ div >
102175 </ div >
103176 ) ;
104177} ;
0 commit comments