mirror of
https://github.com/aaif-goose/goose.git
synced 2026-07-03 14:10:03 +02:00
add flag to hide select voice providers (#7406)
This commit is contained in:
@@ -172,14 +172,12 @@ export const NavigationProvider: React.FC<NavigationProviderProps> = ({ children
|
||||
}, [setIsNavExpanded]);
|
||||
|
||||
useEffect(() => {
|
||||
const handleModeChange = (e: Event) =>
|
||||
setNavigationModeState((e as CustomEvent).detail.mode);
|
||||
const handleModeChange = (e: Event) => setNavigationModeState((e as CustomEvent).detail.mode);
|
||||
const handleStyleChange = (e: Event) =>
|
||||
setNavigationStyleState((e as CustomEvent).detail.style);
|
||||
const handlePositionChange = (e: Event) =>
|
||||
setNavigationPositionState((e as CustomEvent).detail.position);
|
||||
const handlePrefsChange = (e: Event) =>
|
||||
setPreferences((e as CustomEvent).detail);
|
||||
const handlePrefsChange = (e: Event) => setPreferences((e as CustomEvent).detail);
|
||||
|
||||
window.addEventListener('navigation-mode-changed', handleModeChange);
|
||||
window.addEventListener('navigation-style-changed', handleStyleChange);
|
||||
|
||||
@@ -74,7 +74,7 @@ export default function SettingsView({
|
||||
|
||||
useEffect(() => {
|
||||
const handleKeyDown = (event: KeyboardEvent) => {
|
||||
if (event.key === 'Escape') {
|
||||
if (event.key === 'Escape' && !event.defaultPrevented) {
|
||||
onClose();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -6,10 +6,17 @@ import { Input } from '../../ui/input';
|
||||
import { Button } from '../../ui/button';
|
||||
import { trackSettingToggled } from '../../../utils/analytics';
|
||||
import { LocalModelManager } from './LocalModelManager';
|
||||
import { DICTATION_ALLOWED_PROVIDERS } from '../../../updates';
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuRadioGroup,
|
||||
DropdownMenuRadioItem,
|
||||
DropdownMenuTrigger,
|
||||
} from '../../ui/dropdown-menu';
|
||||
|
||||
export const DictationSettings = () => {
|
||||
const [provider, setProvider] = useState<DictationProvider | null>(null);
|
||||
const [showProviderDropdown, setShowProviderDropdown] = useState(false);
|
||||
const [providerStatuses, setProviderStatuses] = useState<Record<string, DictationProviderStatus>>(
|
||||
{}
|
||||
);
|
||||
@@ -17,41 +24,39 @@ export const DictationSettings = () => {
|
||||
const [isEditingKey, setIsEditingKey] = useState(false);
|
||||
const { read, upsert, remove } = useConfig();
|
||||
|
||||
const refreshStatuses = async () => {
|
||||
const audioConfig = await getDictationConfig();
|
||||
setProviderStatuses(audioConfig.data || {});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const loadSettings = async () => {
|
||||
const providerValue = await read('voice_dictation_provider', false);
|
||||
const loadedProvider: DictationProvider | null = (providerValue as DictationProvider) || null;
|
||||
setProvider(loadedProvider);
|
||||
let loadedProvider: DictationProvider | null = (providerValue as DictationProvider) || null;
|
||||
|
||||
const audioConfig = await getDictationConfig();
|
||||
setProviderStatuses(audioConfig.data || {});
|
||||
if (
|
||||
DICTATION_ALLOWED_PROVIDERS &&
|
||||
loadedProvider &&
|
||||
!DICTATION_ALLOWED_PROVIDERS.includes(loadedProvider)
|
||||
) {
|
||||
loadedProvider = null;
|
||||
await upsert('voice_dictation_provider', '', false);
|
||||
}
|
||||
|
||||
setProvider(loadedProvider);
|
||||
await refreshStatuses();
|
||||
};
|
||||
|
||||
loadSettings();
|
||||
}, [read]);
|
||||
}, [read, upsert]);
|
||||
|
||||
const saveProvider = async (newProvider: DictationProvider | null) => {
|
||||
console.log('Saving dictation provider to backend config:', newProvider);
|
||||
const handleProviderChange = (value: string) => {
|
||||
const newProvider = value === 'disabled' ? null : (value as DictationProvider);
|
||||
setProvider(newProvider);
|
||||
await upsert('voice_dictation_provider', newProvider || '', false);
|
||||
upsert('voice_dictation_provider', newProvider || '', false);
|
||||
trackSettingToggled('voice_dictation', newProvider !== null);
|
||||
};
|
||||
|
||||
const handleProviderChange = (newProvider: DictationProvider | null) => {
|
||||
saveProvider(newProvider);
|
||||
setShowProviderDropdown(false);
|
||||
};
|
||||
|
||||
const handleDropdownToggle = async () => {
|
||||
const newShowState = !showProviderDropdown;
|
||||
setShowProviderDropdown(newShowState);
|
||||
|
||||
if (newShowState) {
|
||||
const audioConfig = await getDictationConfig();
|
||||
setProviderStatuses(audioConfig.data || {});
|
||||
}
|
||||
};
|
||||
|
||||
const handleSaveKey = async () => {
|
||||
if (!provider) return;
|
||||
const providerConfig = providerStatuses[provider];
|
||||
@@ -64,9 +69,7 @@ export const DictationSettings = () => {
|
||||
await upsert(keyName, trimmedKey, true);
|
||||
setApiKey('');
|
||||
setIsEditingKey(false);
|
||||
|
||||
const audioConfig = await getDictationConfig();
|
||||
setProviderStatuses(audioConfig.data || {});
|
||||
await refreshStatuses();
|
||||
};
|
||||
|
||||
const handleRemoveKey = async () => {
|
||||
@@ -78,9 +81,7 @@ export const DictationSettings = () => {
|
||||
await remove(keyName, true);
|
||||
setApiKey('');
|
||||
setIsEditingKey(false);
|
||||
|
||||
const audioConfig = await getDictationConfig();
|
||||
setProviderStatuses(audioConfig.data || {});
|
||||
await refreshStatuses();
|
||||
};
|
||||
|
||||
const handleCancelEdit = () => {
|
||||
@@ -88,11 +89,15 @@ export const DictationSettings = () => {
|
||||
setIsEditingKey(false);
|
||||
};
|
||||
|
||||
const getProviderLabel = (provider: DictationProvider | null): string => {
|
||||
if (!provider) return 'Disabled';
|
||||
return provider.charAt(0).toUpperCase() + provider.slice(1);
|
||||
const getProviderLabel = (p: DictationProvider | null): string => {
|
||||
if (!p) return 'Disabled';
|
||||
return p.charAt(0).toUpperCase() + p.slice(1);
|
||||
};
|
||||
|
||||
const visibleProviders = (Object.keys(providerStatuses) as DictationProvider[]).filter(
|
||||
(p) => !DICTATION_ALLOWED_PROVIDERS || DICTATION_ALLOWED_PROVIDERS.includes(p)
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center justify-between py-2 px-2 hover:bg-background-secondary rounded-lg transition-all">
|
||||
@@ -102,47 +107,28 @@ export const DictationSettings = () => {
|
||||
Choose how voice is converted to text
|
||||
</p>
|
||||
</div>
|
||||
<div className="relative">
|
||||
<button
|
||||
onClick={handleDropdownToggle}
|
||||
className="flex items-center gap-2 px-3 py-1.5 text-sm border border-border-primary rounded-md hover:border-border-primary transition-colors text-text-primary bg-background-primary"
|
||||
>
|
||||
<DropdownMenu onOpenChange={(open) => open && refreshStatuses()}>
|
||||
<DropdownMenuTrigger className="flex items-center gap-2 px-3 py-1.5 text-sm border border-border-primary rounded-md hover:border-border-primary transition-colors text-text-primary bg-background-primary">
|
||||
{getProviderLabel(provider)}
|
||||
<ChevronDown className="w-4 h-4" />
|
||||
</button>
|
||||
|
||||
{showProviderDropdown && (
|
||||
<div className="absolute right-0 mt-1 w-max min-w-[250px] max-w-[350px] bg-background-primary border border-border-primary rounded-md shadow-lg z-50">
|
||||
<button
|
||||
onClick={() => handleProviderChange(null)}
|
||||
className="w-full px-3 py-2 text-left text-sm transition-colors hover:bg-background-secondary text-text-primary whitespace-nowrap first:rounded-t-md"
|
||||
>
|
||||
<span className="flex items-center justify-between gap-2">
|
||||
<span>Disabled</span>
|
||||
{provider === null && <span>✓</span>}
|
||||
</span>
|
||||
</button>
|
||||
|
||||
{(Object.keys(providerStatuses) as DictationProvider[]).map((p) => (
|
||||
<button
|
||||
key={p}
|
||||
onClick={() => handleProviderChange(p)}
|
||||
className="w-full px-3 py-2 text-left text-sm transition-colors hover:bg-background-secondary text-text-primary whitespace-nowrap last:rounded-b-md"
|
||||
>
|
||||
<span className="flex items-center justify-between gap-2">
|
||||
<span>
|
||||
{getProviderLabel(p)}
|
||||
{!providerStatuses[p]?.configured && (
|
||||
<span className="text-xs ml-1 text-text-secondary">(not configured)</span>
|
||||
)}
|
||||
</span>
|
||||
{provider === p && <span>✓</span>}
|
||||
</span>
|
||||
</button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end" className="w-max min-w-[250px] max-w-[350px]">
|
||||
<DropdownMenuRadioGroup
|
||||
value={provider ?? 'disabled'}
|
||||
onValueChange={handleProviderChange}
|
||||
>
|
||||
<DropdownMenuRadioItem value="disabled">Disabled</DropdownMenuRadioItem>
|
||||
{visibleProviders.map((p) => (
|
||||
<DropdownMenuRadioItem key={p} value={p}>
|
||||
{getProviderLabel(p)}
|
||||
{!providerStatuses[p]?.configured && (
|
||||
<span className="text-xs ml-1 text-text-secondary">(not configured)</span>
|
||||
)}
|
||||
</DropdownMenuRadioItem>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</DropdownMenuRadioGroup>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
|
||||
{provider && providerStatuses[provider] && (
|
||||
|
||||
@@ -3,3 +3,4 @@ export const COST_TRACKING_ENABLED = true;
|
||||
export const ANNOUNCEMENTS_ENABLED = false;
|
||||
export const CONFIGURATION_ENABLED = true;
|
||||
export const TELEMETRY_UI_ENABLED = true;
|
||||
export const DICTATION_ALLOWED_PROVIDERS: string[] | null = null;
|
||||
|
||||
Reference in New Issue
Block a user