feat: use dropdown for goose selection (#1531)
This commit is contained in:
Generated
+1
-1
@@ -3246,7 +3246,7 @@ dependencies = [
|
|||||||
"nom_locate",
|
"nom_locate",
|
||||||
"rangemap",
|
"rangemap",
|
||||||
"rayon",
|
"rayon",
|
||||||
"thiserror 2.0.11",
|
"thiserror 2.0.12",
|
||||||
"time",
|
"time",
|
||||||
"weezl",
|
"weezl",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { ModelRadioList } from './settings/models/ModelRadioList';
|
|||||||
import { Document, ChevronUp, ChevronDown } from './icons';
|
import { Document, ChevronUp, ChevronDown } from './icons';
|
||||||
import type { View } from '../ChatWindow';
|
import type { View } from '../ChatWindow';
|
||||||
import { getApiUrl, getSecretKey } from '../config';
|
import { getApiUrl, getSecretKey } from '../config';
|
||||||
|
import { BottomMenuModeSelection } from './BottomMenuModeSelection';
|
||||||
|
|
||||||
export default function BottomMenu({
|
export default function BottomMenu({
|
||||||
hasMessages,
|
hasMessages,
|
||||||
@@ -15,11 +16,14 @@ export default function BottomMenu({
|
|||||||
setView: (view: View) => void;
|
setView: (view: View) => void;
|
||||||
}) {
|
}) {
|
||||||
const [isModelMenuOpen, setIsModelMenuOpen] = useState(false);
|
const [isModelMenuOpen, setIsModelMenuOpen] = useState(false);
|
||||||
const [gooseMode, setGooseMode] = useState('auto');
|
|
||||||
const { currentModel } = useModel();
|
const { currentModel } = useModel();
|
||||||
const { recentModels } = useRecentModels(); // Get recent models
|
const { recentModels } = useRecentModels(); // Get recent models
|
||||||
const dropdownRef = useRef<HTMLDivElement>(null);
|
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
|
// Add effect to handle clicks outside
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleClickOutside = (event: MouseEvent) => {
|
const handleClickOutside = (event: MouseEvent) => {
|
||||||
@@ -79,6 +83,41 @@ export default function BottomMenu({
|
|||||||
};
|
};
|
||||||
}, [isModelMenuOpen]);
|
}, [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;
|
let envModelProvider = null;
|
||||||
if (window.electron.getConfig().GOOSE_MODEL && window.electron.getConfig().GOOSE_PROVIDER) {
|
if (window.electron.getConfig().GOOSE_MODEL && window.electron.getConfig().GOOSE_PROVIDER) {
|
||||||
envModelProvider = `${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
|
<span
|
||||||
className="cursor-pointer flex items-center [&>svg]:size-4"
|
className="cursor-pointer flex items-center [&>svg]:size-4"
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
console.log('Opening directory chooser');
|
|
||||||
if (hasMessages) {
|
if (hasMessages) {
|
||||||
window.electron.directoryChooser();
|
window.electron.directoryChooser();
|
||||||
} else {
|
} else {
|
||||||
@@ -103,15 +141,24 @@ export default function BottomMenu({
|
|||||||
<ChevronUp className="ml-1" />
|
<ChevronUp className="ml-1" />
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<div className="relative flex items-center ml-6">
|
{/* Goose Mode Selector Dropdown */}
|
||||||
|
<div className="relative flex items-center ml-6" ref={gooseModeDropdownRef}>
|
||||||
<div
|
<div
|
||||||
className="flex items-center cursor-pointer"
|
className="flex items-center cursor-pointer"
|
||||||
onClick={() => {
|
onClick={() => setIsGooseModeMenuOpen(!isGooseModeMenuOpen)}
|
||||||
setView('settings');
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<span>Goose Mode: {gooseMode}</span>
|
<span>Goose Mode: {gooseMode}</span>
|
||||||
|
{isGooseModeMenuOpen ? (
|
||||||
|
<ChevronDown className="w-4 h-4 ml-1" />
|
||||||
|
) : (
|
||||||
|
<ChevronUp className="w-4 h-4 ml-1" />
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Dropdown Menu */}
|
||||||
|
{isGooseModeMenuOpen && (
|
||||||
|
<BottomMenuModeSelection selectedMode={gooseMode} setSelectedMode={setGooseMode} />
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Model Selector Dropdown - Only in development */}
|
{/* 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