mirror of
https://github.com/block/goose.git
synced 2026-07-17 12:56:20 +02:00
feat: use dropdown for goose selection (#1531)
This commit is contained in:
Generated
+1
-1
@@ -3246,7 +3246,7 @@ dependencies = [
|
||||
"nom_locate",
|
||||
"rangemap",
|
||||
"rayon",
|
||||
"thiserror 2.0.11",
|
||||
"thiserror 2.0.12",
|
||||
"time",
|
||||
"weezl",
|
||||
]
|
||||
|
||||
@@ -6,6 +6,7 @@ import { ModelRadioList } from './settings/models/ModelRadioList';
|
||||
import { Document, ChevronUp, ChevronDown } from './icons';
|
||||
import type { View } from '../ChatWindow';
|
||||
import { getApiUrl, getSecretKey } from '../config';
|
||||
import { BottomMenuModeSelection } from './BottomMenuModeSelection';
|
||||
|
||||
export default function BottomMenu({
|
||||
hasMessages,
|
||||
@@ -15,11 +16,14 @@ export default function BottomMenu({
|
||||
setView: (view: View) => void;
|
||||
}) {
|
||||
const [isModelMenuOpen, setIsModelMenuOpen] = useState(false);
|
||||
const [gooseMode, setGooseMode] = useState('auto');
|
||||
const { currentModel } = useModel();
|
||||
const { recentModels } = useRecentModels(); // Get recent models
|
||||
const dropdownRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const [isGooseModeMenuOpen, setIsGooseModeMenuOpen] = useState(false);
|
||||
const [gooseMode, setGooseMode] = useState('auto');
|
||||
const gooseModeDropdownRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
// Add effect to handle clicks outside
|
||||
useEffect(() => {
|
||||
const handleClickOutside = (event: MouseEvent) => {
|
||||
@@ -79,6 +83,41 @@ export default function BottomMenu({
|
||||
};
|
||||
}, [isModelMenuOpen]);
|
||||
|
||||
useEffect(() => {
|
||||
const handleClickOutside = (event: MouseEvent) => {
|
||||
if (
|
||||
gooseModeDropdownRef.current &&
|
||||
!gooseModeDropdownRef.current.contains(event.target as Node)
|
||||
) {
|
||||
setIsGooseModeMenuOpen(false);
|
||||
}
|
||||
};
|
||||
|
||||
if (isGooseModeMenuOpen) {
|
||||
document.addEventListener('mousedown', handleClickOutside);
|
||||
}
|
||||
|
||||
return () => {
|
||||
document.removeEventListener('mousedown', handleClickOutside);
|
||||
};
|
||||
}, [isGooseModeMenuOpen]);
|
||||
|
||||
useEffect(() => {
|
||||
const handleEsc = (event: KeyboardEvent) => {
|
||||
if (event.key === 'Escape') {
|
||||
setIsGooseModeMenuOpen(false);
|
||||
}
|
||||
};
|
||||
|
||||
if (isGooseModeMenuOpen) {
|
||||
window.addEventListener('keydown', handleEsc);
|
||||
}
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('keydown', handleEsc);
|
||||
};
|
||||
}, [isGooseModeMenuOpen]);
|
||||
|
||||
let envModelProvider = null;
|
||||
if (window.electron.getConfig().GOOSE_MODEL && window.electron.getConfig().GOOSE_PROVIDER) {
|
||||
envModelProvider = `${window.electron.getConfig().GOOSE_MODEL} - ${window.electron.getConfig().GOOSE_PROVIDER}`;
|
||||
@@ -90,7 +129,6 @@ export default function BottomMenu({
|
||||
<span
|
||||
className="cursor-pointer flex items-center [&>svg]:size-4"
|
||||
onClick={async () => {
|
||||
console.log('Opening directory chooser');
|
||||
if (hasMessages) {
|
||||
window.electron.directoryChooser();
|
||||
} else {
|
||||
@@ -103,15 +141,24 @@ export default function BottomMenu({
|
||||
<ChevronUp className="ml-1" />
|
||||
</span>
|
||||
|
||||
<div className="relative flex items-center ml-6">
|
||||
{/* Goose Mode Selector Dropdown */}
|
||||
<div className="relative flex items-center ml-6" ref={gooseModeDropdownRef}>
|
||||
<div
|
||||
className="flex items-center cursor-pointer"
|
||||
onClick={() => {
|
||||
setView('settings');
|
||||
}}
|
||||
onClick={() => setIsGooseModeMenuOpen(!isGooseModeMenuOpen)}
|
||||
>
|
||||
<span>Goose Mode: {gooseMode}</span>
|
||||
{isGooseModeMenuOpen ? (
|
||||
<ChevronDown className="w-4 h-4 ml-1" />
|
||||
) : (
|
||||
<ChevronUp className="w-4 h-4 ml-1" />
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Dropdown Menu */}
|
||||
{isGooseModeMenuOpen && (
|
||||
<BottomMenuModeSelection selectedMode={gooseMode} setSelectedMode={setGooseMode} />
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Model Selector Dropdown - Only in development */}
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
import React from 'react';
|
||||
import { getApiUrl, getSecretKey } from '../config';
|
||||
|
||||
export const BottomMenuModeSelection = ({ selectedMode, setSelectedMode }) => {
|
||||
const modes = [
|
||||
{
|
||||
value: 'auto',
|
||||
},
|
||||
{
|
||||
value: 'approve',
|
||||
},
|
||||
{
|
||||
value: 'chat',
|
||||
},
|
||||
];
|
||||
|
||||
const handleModeChange = async (newMode: string) => {
|
||||
const storeResponse = await fetch(getApiUrl('/configs/store'), {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Secret-Key': getSecretKey(),
|
||||
},
|
||||
body: JSON.stringify({
|
||||
key: 'GOOSE_MODE',
|
||||
value: newMode,
|
||||
isSecret: false,
|
||||
}),
|
||||
});
|
||||
|
||||
if (!storeResponse.ok) {
|
||||
const errorText = await storeResponse.text();
|
||||
console.error('Store response error:', errorText);
|
||||
throw new Error(`Failed to store new goose mode: ${newMode}`);
|
||||
}
|
||||
setSelectedMode(newMode);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="absolute bottom-[24px] right-0 w-[120px] bg-bgApp rounded-lg border border-borderSubtle">
|
||||
<div>
|
||||
{modes.map((mode) => (
|
||||
<label key={mode.value} className="block cursor-pointer">
|
||||
<div
|
||||
className="flex items-center justify-between p-2 text-textStandard hover:bg-bgSubtle transition-colors"
|
||||
onClick={() => handleModeChange(mode.value)}
|
||||
>
|
||||
<div>
|
||||
<p className="text-sm">{mode.value}</p>
|
||||
</div>
|
||||
<div className="relative">
|
||||
<input
|
||||
type="radio"
|
||||
name="modes"
|
||||
value={mode.value}
|
||||
checked={selectedMode === mode.value}
|
||||
onChange={() => handleModeChange(mode.value)}
|
||||
className="peer sr-only"
|
||||
/>
|
||||
<div
|
||||
className="h-4 w-4 rounded-full border border-gray-400 dark:border-gray-500
|
||||
peer-checked:border-[6px] peer-checked:border-black dark:peer-checked:border-white
|
||||
peer-checked:bg-white dark:peer-checked:bg-black
|
||||
transition-all duration-200 ease-in-out"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user