feat: settings v2 scaffolding (#1374)
This commit is contained in:
+21
-10
@@ -14,6 +14,7 @@ import { extractExtensionName } from './components/settings/extensions/utils';
|
|||||||
import WelcomeView from './components/WelcomeView';
|
import WelcomeView from './components/WelcomeView';
|
||||||
import ChatView from './components/ChatView';
|
import ChatView from './components/ChatView';
|
||||||
import SettingsView, { type SettingsViewOptions } from './components/settings/SettingsView';
|
import SettingsView, { type SettingsViewOptions } from './components/settings/SettingsView';
|
||||||
|
import SettingsViewV2 from './components/settings_v2/SettingsView';
|
||||||
import MoreModelsView from './components/settings/models/MoreModelsView';
|
import MoreModelsView from './components/settings/models/MoreModelsView';
|
||||||
import ConfigureProvidersView from './components/settings/providers/ConfigureProvidersView';
|
import ConfigureProvidersView from './components/settings/providers/ConfigureProvidersView';
|
||||||
import ProviderSettings from './components/settings/providers/providers/NewProviderSettingsPage';
|
import ProviderSettings from './components/settings/providers/providers/NewProviderSettingsPage';
|
||||||
@@ -28,7 +29,8 @@ export type View =
|
|||||||
| 'moreModels'
|
| 'moreModels'
|
||||||
| 'configureProviders'
|
| 'configureProviders'
|
||||||
| 'configPage'
|
| 'configPage'
|
||||||
| 'alphaConfigureProviders';
|
| 'alphaConfigureProviders'
|
||||||
|
| 'settingsV2';
|
||||||
|
|
||||||
export type ViewConfig = {
|
export type ViewConfig = {
|
||||||
view: View;
|
view: View;
|
||||||
@@ -202,15 +204,24 @@ export default function App() {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{view === 'settings' && (
|
{view === 'settings' &&
|
||||||
<SettingsView
|
(process.env.ALPHA ? (
|
||||||
onClose={() => {
|
<SettingsViewV2
|
||||||
setView('chat');
|
onClose={() => {
|
||||||
}}
|
setView('chat');
|
||||||
setView={setView}
|
}}
|
||||||
viewOptions={viewOptions as SettingsViewOptions}
|
setView={setView}
|
||||||
/>
|
viewOptions={viewOptions as SettingsViewOptions}
|
||||||
)}
|
/>
|
||||||
|
) : (
|
||||||
|
<SettingsView
|
||||||
|
onClose={() => {
|
||||||
|
setView('chat');
|
||||||
|
}}
|
||||||
|
setView={setView}
|
||||||
|
viewOptions={viewOptions as SettingsViewOptions}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
{view === 'moreModels' && (
|
{view === 'moreModels' && (
|
||||||
<MoreModelsView
|
<MoreModelsView
|
||||||
onClose={() => {
|
onClose={() => {
|
||||||
|
|||||||
@@ -0,0 +1,206 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { ScrollArea } from '../ui/scroll-area';
|
||||||
|
import BackButton from '../ui/BackButton';
|
||||||
|
import type { View } from '../../App';
|
||||||
|
import { Button } from '../ui/button';
|
||||||
|
import { Switch } from '../ui/switch';
|
||||||
|
import { Plus } from 'lucide-react';
|
||||||
|
import { Gear } from '../icons/Gear';
|
||||||
|
import { GPSIcon } from '../ui/icons';
|
||||||
|
|
||||||
|
interface ModelOption {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
selected: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ExtensionItem {
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
subtitle: string;
|
||||||
|
enabled: boolean;
|
||||||
|
canConfigure?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mock data - replace with actual data source
|
||||||
|
const defaultModelOptions: ModelOption[] = [
|
||||||
|
{
|
||||||
|
id: 'gpt-4',
|
||||||
|
name: 'GPT-4',
|
||||||
|
description: 'Most capable model, best for complex tasks',
|
||||||
|
selected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'gpt-3.5',
|
||||||
|
name: 'GPT-3.5',
|
||||||
|
description: 'Fast and efficient for most tasks',
|
||||||
|
selected: false,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const extensionItems: ExtensionItem[] = [
|
||||||
|
{
|
||||||
|
id: 'dev',
|
||||||
|
title: 'Developer Tools',
|
||||||
|
subtitle: 'Code editing and shell access',
|
||||||
|
enabled: true,
|
||||||
|
canConfigure: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'browser',
|
||||||
|
title: 'Web Browser',
|
||||||
|
subtitle: 'Internet access and web automation',
|
||||||
|
enabled: false,
|
||||||
|
canConfigure: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export type SettingsViewOptions = {
|
||||||
|
extensionId?: string;
|
||||||
|
showEnvVars?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function SettingsView({
|
||||||
|
onClose,
|
||||||
|
setView,
|
||||||
|
viewOptions,
|
||||||
|
}: {
|
||||||
|
onClose: () => void;
|
||||||
|
setView: (view: View) => void;
|
||||||
|
viewOptions: SettingsViewOptions;
|
||||||
|
}) {
|
||||||
|
const [modelOptions, setModelOptions] = React.useState<ModelOption[]>(defaultModelOptions);
|
||||||
|
const [extensions, setExtensions] = React.useState<ExtensionItem[]>(extensionItems);
|
||||||
|
|
||||||
|
const handleModelSelect = (selectedId: string) => {
|
||||||
|
setModelOptions(
|
||||||
|
modelOptions.map((model) => ({
|
||||||
|
...model,
|
||||||
|
selected: model.id === selectedId,
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleExtensionToggle = (id: string) => {
|
||||||
|
setExtensions(
|
||||||
|
extensions.map((extension) => ({
|
||||||
|
...extension,
|
||||||
|
enabled: extension.id === id ? !extension.enabled : extension.enabled,
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="h-screen w-full">
|
||||||
|
<div className="relative flex items-center h-[36px] w-full bg-bgSubtle"></div>
|
||||||
|
|
||||||
|
<ScrollArea className="h-full w-full">
|
||||||
|
<div className="flex flex-col pb-24">
|
||||||
|
<div className="px-8 pt-6 pb-4">
|
||||||
|
<BackButton onClick={() => onClose()} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Content Area */}
|
||||||
|
<div className="flex-1 pt-[20px]">
|
||||||
|
<div className="space-y-8">
|
||||||
|
{/* Models Section */}
|
||||||
|
<section id="models">
|
||||||
|
<div className="flex justify-between items-center mb-6 px-8">
|
||||||
|
<h1 className="text-3xl font-medium text-textStandard">Models</h1>
|
||||||
|
</div>
|
||||||
|
<div className="px-8">
|
||||||
|
<div className="space-y-2">
|
||||||
|
{modelOptions.map((model, index) => (
|
||||||
|
<React.Fragment key={model.id}>
|
||||||
|
<div className="flex items-center justify-between py-3">
|
||||||
|
<div className="space-y-1">
|
||||||
|
<h3 className="font-medium text-textStandard">{model.name}</h3>
|
||||||
|
<p className="text-sm text-textSubtle">{model.description}</p>
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
name="model"
|
||||||
|
checked={model.selected}
|
||||||
|
onChange={() => handleModelSelect(model.id)}
|
||||||
|
className="h-4 w-4 text-white accent-[#393838] bg-[#393838] border-[#393838] checked:bg-[#393838] focus:ring-0 focus:ring-offset-0"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{index < modelOptions.length - 1 && (
|
||||||
|
<div className="h-px bg-borderSubtle" />
|
||||||
|
)}
|
||||||
|
</React.Fragment>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<div className="flex gap-4 pt-4 w-full">
|
||||||
|
<Button className="flex items-center gap-2 flex-1 justify-center bg-[#393838] hover:bg-subtle">
|
||||||
|
<Plus className="h-4 w-4" />
|
||||||
|
Add Model
|
||||||
|
</Button>
|
||||||
|
<Button className="flex items-center gap-2 flex-1 justify-center text-textSubtle border-standard bg-grey-60 hover:bg-subtle">
|
||||||
|
<Gear className="h-4 w-4" />
|
||||||
|
Configure Providers
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* Extensions Section */}
|
||||||
|
<section id="extensions">
|
||||||
|
<div className="flex justify-between items-center mb-6 px-8">
|
||||||
|
<h1 className="text-3xl font-medium text-textStandard">Extensions</h1>
|
||||||
|
</div>
|
||||||
|
<div className="px-8">
|
||||||
|
<p className="text-sm text-textStandard mb-6">
|
||||||
|
These extensions use the Model Context Protocol (MCP). They can expand Goose's
|
||||||
|
capabilities using three main components: Prompts, Resources, and Tools.
|
||||||
|
</p>
|
||||||
|
<div className="space-y-2">
|
||||||
|
{extensions.map((extension, index) => (
|
||||||
|
<React.Fragment key={extension.id}>
|
||||||
|
<div className="flex items-center justify-between py-3">
|
||||||
|
<div className="space-y-1">
|
||||||
|
<h3 className="font-medium text-textStandard">{extension.title}</h3>
|
||||||
|
<p className="text-sm text-textSubtle">{extension.subtitle}</p>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-4">
|
||||||
|
{extension.canConfigure && (
|
||||||
|
<button className="text-textSubtle hover:text-textStandard">
|
||||||
|
<Gear className="h-5 w-5" />
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
<Switch
|
||||||
|
checked={extension.enabled}
|
||||||
|
onCheckedChange={() => handleExtensionToggle(extension.id)}
|
||||||
|
className="bg-[#393838] [&_span[data-state]]:bg-white"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{index < extensions.length - 1 && <div className="h-px bg-borderSubtle" />}
|
||||||
|
</React.Fragment>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<div className="flex gap-4 pt-4 w-full">
|
||||||
|
<Button className="flex items-center gap-2 flex-1 justify-center bg-[#393838] hover:bg-subtle">
|
||||||
|
<Plus className="h-4 w-4" />
|
||||||
|
Manually Add
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
className="flex items-center gap-2 flex-1 justify-center text-textSubtle border-standard bg-grey-60 hover:bg-subtle"
|
||||||
|
onClick={() =>
|
||||||
|
window.open('https://block.github.io/goose/v1/extensions/', '_blank')
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<GPSIcon size={18} />
|
||||||
|
Visit Extensions
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ScrollArea>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -23,7 +23,7 @@ const BackButton: React.FC<BackButtonProps> = ({ onClick, className = '' }) => {
|
|||||||
className={`flex items-center text-sm text-textSubtle group hover:text-textStandard ${className}`}
|
className={`flex items-center text-sm text-textSubtle group hover:text-textStandard ${className}`}
|
||||||
>
|
>
|
||||||
<Back className="w-3 h-3 group-hover:-translate-x-1 transition-all mr-1" />
|
<Back className="w-3 h-3 group-hover:-translate-x-1 transition-all mr-1" />
|
||||||
<span>Back</span>
|
<span>Exit</span>
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user