Workspaces in Workspaces all around
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { useState, useEffect, useMemo } from 'react';
|
||||
import { toast } from 'sonner';
|
||||
import { Terminal, Eye, Trash2 } from 'lucide-react';
|
||||
import { Terminal, Eye, Trash2, Bot } from 'lucide-react';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { Button } from '@/components/ui/button';
|
||||
@@ -10,7 +10,10 @@ import { Switch } from '@/components/ui/switch';
|
||||
import { Tabs, TabsList, TabsTrigger, TabsContent } from '@/components/ui/tabs';
|
||||
import { Accordion, AccordionItem, AccordionTrigger, AccordionContent } from '@/components/ui/accordion';
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
||||
import { Card } from '@/components/Card';
|
||||
import type { LayoutNode, PanelComponents } from '@/components/Workspace';
|
||||
import { WorkspaceLayout } from '@/components/Workspace';
|
||||
import { appRegistry } from '../Workspaces/app-registry';
|
||||
import { createSettingsPanelComponents, type SettingsSection } from './SettingsPanel';
|
||||
import { useSettings } from '@/state/useSettings';
|
||||
import { useUserState } from '@/state/useUserState';
|
||||
import {
|
||||
@@ -21,38 +24,47 @@ import {
|
||||
} from '@/state/useModels';
|
||||
import type { UserSettings } from '@/state/types/user-settings';
|
||||
|
||||
const GLOBAL_KEY = 'AI_SETTINGS_SELECTED';
|
||||
|
||||
const sections: SettingsSection[] = [
|
||||
{ key: 'chat-defaults', icon: Terminal, title: 'Chat Defaults', description: 'Model, prompt, and temperature', content: <ChatDefaultsSection /> },
|
||||
{ key: 'model-visibility', icon: Eye, title: 'Model Visibility', description: 'Enable or disable models', content: <ModelVisibilitySection /> },
|
||||
];
|
||||
|
||||
const { Sidebar, Content } = createSettingsPanelComponents({
|
||||
globalKey: GLOBAL_KEY,
|
||||
sidebarIcon: Bot,
|
||||
sidebarLabel: 'AI',
|
||||
sections,
|
||||
});
|
||||
|
||||
const layout: LayoutNode = {
|
||||
type: 'group',
|
||||
id: 'ai-root',
|
||||
direction: 'horizontal',
|
||||
children: [
|
||||
{ node: { type: 'panel', id: 'ai-left', appType: null }, size: 20 },
|
||||
{ node: { type: 'panel', id: 'ai-right', appType: null }, size: 80 },
|
||||
],
|
||||
};
|
||||
|
||||
export const AISettings = () => {
|
||||
const [mainTab, setMainTab] = useUserState('ai-settings-tab', 'chat-defaults');
|
||||
const panelComponents: PanelComponents = useMemo(
|
||||
() => ({
|
||||
'ai-left': Sidebar,
|
||||
'ai-right': Content,
|
||||
}),
|
||||
[],
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="flex justify-center h-full px-4 py-8 overflow-y-auto">
|
||||
<Card className="w-full max-w-2xl h-fit p-6">
|
||||
<Tabs value={mainTab} onValueChange={setMainTab}>
|
||||
<TabsList className="w-full mb-6">
|
||||
<TabsTrigger value="chat-defaults" className="flex-1 gap-2 cursor-pointer">
|
||||
<Terminal className="h-4 w-4" />
|
||||
Chat Defaults
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="model-visibility" className="flex-1 gap-2 cursor-pointer">
|
||||
<Eye className="h-4 w-4" />
|
||||
Model Visibility
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
|
||||
<TabsContent value="chat-defaults">
|
||||
<ChatDefaultsSection />
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="model-visibility">
|
||||
<ModelVisibilitySection />
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
</Card>
|
||||
<div className="h-full w-full pt-2">
|
||||
<WorkspaceLayout layout={layout} onLayoutChange={() => {}} registry={appRegistry} components={panelComponents} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const ChatDefaultsSection = () => {
|
||||
function ChatDefaultsSection() {
|
||||
const { settings, saveSettings } = useSettings();
|
||||
const claudeModels = useVisibleClaudeModels();
|
||||
const openCodeModels = useVisibleOpenCodeModels();
|
||||
@@ -102,7 +114,7 @@ const ChatDefaultsSection = () => {
|
||||
<Label className="grid gap-2">
|
||||
<span className="text-duck-dark/70">Model</span>
|
||||
<Select value={model ?? ''} onValueChange={(v) => setModel(v || null)}>
|
||||
<SelectTrigger className="h-11 bg-white/60 border-duck-dark/20 text-duck-dark">
|
||||
<SelectTrigger className="h-11 bg-background/60 border-duck-dark/20 text-duck-dark">
|
||||
<SelectValue placeholder="Default" />
|
||||
</SelectTrigger>
|
||||
<SelectContent className="z-[600]">
|
||||
@@ -119,7 +131,7 @@ const ChatDefaultsSection = () => {
|
||||
<Label className="grid gap-2">
|
||||
<span className="text-duck-dark/70">System Prompt</span>
|
||||
<Textarea
|
||||
className="bg-white/60 border-duck-dark/20 text-duck-dark placeholder:text-duck-dark/40 min-h-[100px]"
|
||||
className="bg-background/60 border-duck-dark/20 text-duck-dark placeholder:text-duck-dark/40 min-h-[100px]"
|
||||
placeholder="Custom instructions for the AI..."
|
||||
value={systemPrompt}
|
||||
onChange={(ev) => setSystemPrompt(ev.target.value)}
|
||||
@@ -137,7 +149,7 @@ const ChatDefaultsSection = () => {
|
||||
<Label className="grid gap-2">
|
||||
<span className="text-duck-dark/70">Default Working Directory</span>
|
||||
<Input
|
||||
className="h-11 bg-white/60 border-duck-dark/20 text-duck-dark placeholder:text-duck-dark/40"
|
||||
className="h-11 bg-background/60 border-duck-dark/20 text-duck-dark placeholder:text-duck-dark/40"
|
||||
value={defaultPwd}
|
||||
onChange={(ev) => setDefaultPwd(ev.target.value)}
|
||||
placeholder="~"
|
||||
@@ -154,9 +166,9 @@ const ChatDefaultsSection = () => {
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
const ModelVisibilitySection = () => {
|
||||
function ModelVisibilitySection() {
|
||||
const { settings, saveSettings } = useSettings();
|
||||
const claudeModels = useClaudeModels();
|
||||
const openCodeModels = useOpenCodeModels();
|
||||
@@ -234,7 +246,7 @@ const ModelVisibilitySection = () => {
|
||||
{addingProvider ? (
|
||||
<>
|
||||
<Select value={selectedNewProvider} onValueChange={setSelectedNewProvider}>
|
||||
<SelectTrigger className="h-9 flex-1 bg-white/60 border-duck-dark/20 text-duck-dark text-sm">
|
||||
<SelectTrigger className="h-9 flex-1 bg-background/60 border-duck-dark/20 text-duck-dark text-sm">
|
||||
<SelectValue placeholder="Select provider..." />
|
||||
</SelectTrigger>
|
||||
<SelectContent className="z-[600]">
|
||||
@@ -282,7 +294,7 @@ const ModelVisibilitySection = () => {
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
type ProviderGroup = { provider: string; models: { id: string; name: string }[] };
|
||||
|
||||
|
||||
Reference in New Issue
Block a user