diff --git a/src/components/settings/view/tabs/agents-settings/AgentsSettingsTab.tsx b/src/components/settings/view/tabs/agents-settings/AgentsSettingsTab.tsx index 2101e9e..7bc9389 100644 --- a/src/components/settings/view/tabs/agents-settings/AgentsSettingsTab.tsx +++ b/src/components/settings/view/tabs/agents-settings/AgentsSettingsTab.tsx @@ -1,52 +1,9 @@ import { useMemo, useState } from 'react'; -import { useTranslation } from 'react-i18next'; -import AgentListItem from './AgentListItem'; -import AccountContent from './AccountContent'; -import McpServersContent from './McpServersContent'; -import PermissionsContent from './PermissionsContent'; -import type { - AgentCategory, - AgentProvider, - AuthStatus, - ClaudePermissionsState, - CodexPermissionMode, - CursorPermissionsState, - McpServer, - McpToolsResult, - McpTestResult, -} from '../../../types/types'; - -type AgentsSettingsTabProps = { - claudeAuthStatus: AuthStatus; - cursorAuthStatus: AuthStatus; - codexAuthStatus: AuthStatus; - onClaudeLogin: () => void; - onCursorLogin: () => void; - onCodexLogin: () => void; - claudePermissions: ClaudePermissionsState; - onClaudePermissionsChange: (value: ClaudePermissionsState) => void; - cursorPermissions: CursorPermissionsState; - onCursorPermissionsChange: (value: CursorPermissionsState) => void; - codexPermissionMode: CodexPermissionMode; - onCodexPermissionModeChange: (value: CodexPermissionMode) => void; - mcpServers: McpServer[]; - cursorMcpServers: McpServer[]; - codexMcpServers: McpServer[]; - mcpTestResults: Record; - mcpServerTools: Record; - mcpToolsLoading: Record; - onOpenMcpForm: (server?: McpServer) => void; - onDeleteMcpServer: (serverId: string, scope?: string) => void; - onTestMcpServer: (serverId: string, scope?: string) => void; - onDiscoverMcpTools: (serverId: string, scope?: string) => void; - onOpenCodexMcpForm: (server?: McpServer) => void; - onDeleteCodexMcpServer: (serverId: string) => void; -}; - -type AgentContext = { - authStatus: AuthStatus; - onLogin: () => void; -}; +import type { AgentCategory, AgentProvider } from '../../../types/types'; +import AgentCategoryContentSection from './sections/AgentCategoryContentSection'; +import AgentCategoryTabsSection from './sections/AgentCategoryTabsSection'; +import AgentSelectorSection from './sections/AgentSelectorSection'; +import type { AgentContext, AgentsSettingsTabProps } from './types'; export default function AgentsSettingsTab({ claudeAuthStatus, @@ -74,11 +31,8 @@ export default function AgentsSettingsTab({ onOpenCodexMcpForm, onDeleteCodexMcpServer, }: AgentsSettingsTabProps) { - const { t } = useTranslation('settings'); const [selectedAgent, setSelectedAgent] = useState('claude'); const [selectedCategory, setSelectedCategory] = useState('account'); - // Cursor MCP add/edit/delete was previously a placeholder and is intentionally preserved. - const noopCursorMcpAction = () => {}; const agentContextById = useMemo>(() => ({ claude: { @@ -104,144 +58,41 @@ export default function AgentsSettingsTab({ return (
-
-
- {(['claude', 'cursor', 'codex'] as AgentProvider[]).map((agent) => ( - setSelectedAgent(agent)} - isMobile - /> - ))} -
-
- -
-
- {(['claude', 'cursor', 'codex'] as AgentProvider[]).map((agent) => ( - setSelectedAgent(agent)} - /> - ))} -
-
+
-
-
- {(['account', 'permissions', 'mcp'] as AgentCategory[]).map((category) => ( - - ))} -
-
+ -
- {selectedCategory === 'account' && ( - - )} - - {selectedCategory === 'permissions' && selectedAgent === 'claude' && ( - { - onClaudePermissionsChange({ ...claudePermissions, skipPermissions: value }); - }} - allowedTools={claudePermissions.allowedTools} - onAllowedToolsChange={(value) => { - onClaudePermissionsChange({ ...claudePermissions, allowedTools: value }); - }} - disallowedTools={claudePermissions.disallowedTools} - onDisallowedToolsChange={(value) => { - onClaudePermissionsChange({ ...claudePermissions, disallowedTools: value }); - }} - /> - )} - - {selectedCategory === 'permissions' && selectedAgent === 'cursor' && ( - { - onCursorPermissionsChange({ ...cursorPermissions, skipPermissions: value }); - }} - allowedCommands={cursorPermissions.allowedCommands} - onAllowedCommandsChange={(value) => { - onCursorPermissionsChange({ ...cursorPermissions, allowedCommands: value }); - }} - disallowedCommands={cursorPermissions.disallowedCommands} - onDisallowedCommandsChange={(value) => { - onCursorPermissionsChange({ ...cursorPermissions, disallowedCommands: value }); - }} - /> - )} - - {selectedCategory === 'permissions' && selectedAgent === 'codex' && ( - - )} - - {selectedCategory === 'mcp' && selectedAgent === 'claude' && ( - onOpenMcpForm()} - onEdit={(server) => onOpenMcpForm(server)} - onDelete={onDeleteMcpServer} - onTest={onTestMcpServer} - onDiscoverTools={onDiscoverMcpTools} - testResults={mcpTestResults} - serverTools={mcpServerTools} - toolsLoading={mcpToolsLoading} - /> - )} - - {selectedCategory === 'mcp' && selectedAgent === 'cursor' && ( - - )} - - {selectedCategory === 'mcp' && selectedAgent === 'codex' && ( - onOpenCodexMcpForm()} - onEdit={(server) => onOpenCodexMcpForm(server)} - onDelete={(serverId) => onDeleteCodexMcpServer(serverId)} - /> - )} -
+
); diff --git a/src/components/settings/view/tabs/agents-settings/sections/AgentCategoryContentSection.tsx b/src/components/settings/view/tabs/agents-settings/sections/AgentCategoryContentSection.tsx new file mode 100644 index 0000000..a20c8ff --- /dev/null +++ b/src/components/settings/view/tabs/agents-settings/sections/AgentCategoryContentSection.tsx @@ -0,0 +1,122 @@ +import AccountContent from './content/AccountContent'; +import McpServersContent from './content/McpServersContent'; +import PermissionsContent from './content/PermissionsContent'; +import type { AgentCategoryContentSectionProps } from '../types'; + +export default function AgentCategoryContentSection({ + selectedAgent, + selectedCategory, + agentContextById, + claudePermissions, + onClaudePermissionsChange, + cursorPermissions, + onCursorPermissionsChange, + codexPermissionMode, + onCodexPermissionModeChange, + mcpServers, + cursorMcpServers, + codexMcpServers, + mcpTestResults, + mcpServerTools, + mcpToolsLoading, + onOpenMcpForm, + onDeleteMcpServer, + onTestMcpServer, + onDiscoverMcpTools, + onOpenCodexMcpForm, + onDeleteCodexMcpServer, +}: AgentCategoryContentSectionProps) { + // Cursor MCP add/edit/delete was previously a placeholder and is intentionally preserved. + const noopCursorMcpAction = () => {}; + + return ( +
+ {selectedCategory === 'account' && ( + + )} + + {selectedCategory === 'permissions' && selectedAgent === 'claude' && ( + { + onClaudePermissionsChange({ ...claudePermissions, skipPermissions: value }); + }} + allowedTools={claudePermissions.allowedTools} + onAllowedToolsChange={(value) => { + onClaudePermissionsChange({ ...claudePermissions, allowedTools: value }); + }} + disallowedTools={claudePermissions.disallowedTools} + onDisallowedToolsChange={(value) => { + onClaudePermissionsChange({ ...claudePermissions, disallowedTools: value }); + }} + /> + )} + + {selectedCategory === 'permissions' && selectedAgent === 'cursor' && ( + { + onCursorPermissionsChange({ ...cursorPermissions, skipPermissions: value }); + }} + allowedCommands={cursorPermissions.allowedCommands} + onAllowedCommandsChange={(value) => { + onCursorPermissionsChange({ ...cursorPermissions, allowedCommands: value }); + }} + disallowedCommands={cursorPermissions.disallowedCommands} + onDisallowedCommandsChange={(value) => { + onCursorPermissionsChange({ ...cursorPermissions, disallowedCommands: value }); + }} + /> + )} + + {selectedCategory === 'permissions' && selectedAgent === 'codex' && ( + + )} + + {selectedCategory === 'mcp' && selectedAgent === 'claude' && ( + onOpenMcpForm()} + onEdit={(server) => onOpenMcpForm(server)} + onDelete={onDeleteMcpServer} + onTest={onTestMcpServer} + onDiscoverTools={onDiscoverMcpTools} + testResults={mcpTestResults} + serverTools={mcpServerTools} + toolsLoading={mcpToolsLoading} + /> + )} + + {selectedCategory === 'mcp' && selectedAgent === 'cursor' && ( + + )} + + {selectedCategory === 'mcp' && selectedAgent === 'codex' && ( + onOpenCodexMcpForm()} + onEdit={(server) => onOpenCodexMcpForm(server)} + onDelete={(serverId) => onDeleteCodexMcpServer(serverId)} + /> + )} +
+ ); +} diff --git a/src/components/settings/view/tabs/agents-settings/sections/AgentCategoryTabsSection.tsx b/src/components/settings/view/tabs/agents-settings/sections/AgentCategoryTabsSection.tsx new file mode 100644 index 0000000..d611ccc --- /dev/null +++ b/src/components/settings/view/tabs/agents-settings/sections/AgentCategoryTabsSection.tsx @@ -0,0 +1,34 @@ +import { useTranslation } from 'react-i18next'; +import type { AgentCategory } from '../../../../types/types'; +import type { AgentCategoryTabsSectionProps } from '../types'; + +const AGENT_CATEGORIES: AgentCategory[] = ['account', 'permissions', 'mcp']; + +export default function AgentCategoryTabsSection({ + selectedCategory, + onSelectCategory, +}: AgentCategoryTabsSectionProps) { + const { t } = useTranslation('settings'); + + return ( +
+
+ {AGENT_CATEGORIES.map((category) => ( + + ))} +
+
+ ); +} diff --git a/src/components/settings/view/tabs/agents-settings/sections/AgentSelectorSection.tsx b/src/components/settings/view/tabs/agents-settings/sections/AgentSelectorSection.tsx new file mode 100644 index 0000000..79559e2 --- /dev/null +++ b/src/components/settings/view/tabs/agents-settings/sections/AgentSelectorSection.tsx @@ -0,0 +1,44 @@ +import type { AgentProvider } from '../../../../types/types'; +import AgentListItem from '../AgentListItem'; +import type { AgentSelectorSectionProps } from '../types'; + +const AGENT_PROVIDERS: AgentProvider[] = ['claude', 'cursor', 'codex']; + +export default function AgentSelectorSection({ + selectedAgent, + onSelectAgent, + agentContextById, +}: AgentSelectorSectionProps) { + return ( + <> +
+
+ {AGENT_PROVIDERS.map((agent) => ( + onSelectAgent(agent)} + isMobile + /> + ))} +
+
+ +
+
+ {AGENT_PROVIDERS.map((agent) => ( + onSelectAgent(agent)} + /> + ))} +
+
+ + ); +} diff --git a/src/components/settings/view/tabs/agents-settings/AccountContent.tsx b/src/components/settings/view/tabs/agents-settings/sections/content/AccountContent.tsx similarity index 95% rename from src/components/settings/view/tabs/agents-settings/AccountContent.tsx rename to src/components/settings/view/tabs/agents-settings/sections/content/AccountContent.tsx index 9dcd735..6fa015c 100644 --- a/src/components/settings/view/tabs/agents-settings/AccountContent.tsx +++ b/src/components/settings/view/tabs/agents-settings/sections/content/AccountContent.tsx @@ -1,9 +1,9 @@ import { LogIn } from 'lucide-react'; import { useTranslation } from 'react-i18next'; -import { Badge } from '../../../../ui/badge'; -import { Button } from '../../../../ui/button'; -import SessionProviderLogo from '../../../../SessionProviderLogo'; -import type { AgentProvider, AuthStatus } from '../../../types/types'; +import { Badge } from '../../../../../../ui/badge'; +import { Button } from '../../../../../../ui/button'; +import SessionProviderLogo from '../../../../../../SessionProviderLogo'; +import type { AgentProvider, AuthStatus } from '../../../../../types/types'; type AccountContentProps = { agent: AgentProvider; diff --git a/src/components/settings/view/tabs/agents-settings/McpServersContent.tsx b/src/components/settings/view/tabs/agents-settings/sections/content/McpServersContent.tsx similarity index 99% rename from src/components/settings/view/tabs/agents-settings/McpServersContent.tsx rename to src/components/settings/view/tabs/agents-settings/sections/content/McpServersContent.tsx index ca9ba95..4569e6d 100644 --- a/src/components/settings/view/tabs/agents-settings/McpServersContent.tsx +++ b/src/components/settings/view/tabs/agents-settings/sections/content/McpServersContent.tsx @@ -1,8 +1,8 @@ import { Edit3, Globe, Plus, Server, Terminal, Trash2, Zap } from 'lucide-react'; import { useTranslation } from 'react-i18next'; -import { Badge } from '../../../../ui/badge'; -import { Button } from '../../../../ui/button'; -import type { McpServer, McpToolsResult, McpTestResult } from '../../../types/types'; +import { Badge } from '../../../../../../ui/badge'; +import { Button } from '../../../../../../ui/button'; +import type { McpServer, McpToolsResult, McpTestResult } from '../../../../../types/types'; const getTransportIcon = (type: string | undefined) => { if (type === 'stdio') { diff --git a/src/components/settings/view/tabs/agents-settings/PermissionsContent.tsx b/src/components/settings/view/tabs/agents-settings/sections/content/PermissionsContent.tsx similarity index 99% rename from src/components/settings/view/tabs/agents-settings/PermissionsContent.tsx rename to src/components/settings/view/tabs/agents-settings/sections/content/PermissionsContent.tsx index 5e03772..10f77be 100644 --- a/src/components/settings/view/tabs/agents-settings/PermissionsContent.tsx +++ b/src/components/settings/view/tabs/agents-settings/sections/content/PermissionsContent.tsx @@ -1,9 +1,9 @@ import { useState } from 'react'; import { AlertTriangle, Plus, Shield, X } from 'lucide-react'; import { useTranslation } from 'react-i18next'; -import { Button } from '../../../../ui/button'; -import { Input } from '../../../../ui/input'; -import type { CodexPermissionMode } from '../../../types/types'; +import { Button } from '../../../../../../ui/button'; +import { Input } from '../../../../../../ui/input'; +import type { CodexPermissionMode } from '../../../../../types/types'; const COMMON_CLAUDE_TOOLS = [ 'Bash(git log:*)', diff --git a/src/components/settings/view/tabs/agents-settings/types.ts b/src/components/settings/view/tabs/agents-settings/types.ts new file mode 100644 index 0000000..60ebaec --- /dev/null +++ b/src/components/settings/view/tabs/agents-settings/types.ts @@ -0,0 +1,80 @@ +import type { + AgentProvider, + AuthStatus, + AgentCategory, + ClaudePermissionsState, + CodexPermissionMode, + CursorPermissionsState, + McpServer, + McpToolsResult, + McpTestResult, +} from '../../../types/types'; + +export type AgentContext = { + authStatus: AuthStatus; + onLogin: () => void; +}; + +export type AgentContextByProvider = Record; + +export type AgentsSettingsTabProps = { + claudeAuthStatus: AuthStatus; + cursorAuthStatus: AuthStatus; + codexAuthStatus: AuthStatus; + onClaudeLogin: () => void; + onCursorLogin: () => void; + onCodexLogin: () => void; + claudePermissions: ClaudePermissionsState; + onClaudePermissionsChange: (value: ClaudePermissionsState) => void; + cursorPermissions: CursorPermissionsState; + onCursorPermissionsChange: (value: CursorPermissionsState) => void; + codexPermissionMode: CodexPermissionMode; + onCodexPermissionModeChange: (value: CodexPermissionMode) => void; + mcpServers: McpServer[]; + cursorMcpServers: McpServer[]; + codexMcpServers: McpServer[]; + mcpTestResults: Record; + mcpServerTools: Record; + mcpToolsLoading: Record; + onOpenMcpForm: (server?: McpServer) => void; + onDeleteMcpServer: (serverId: string, scope?: string) => void; + onTestMcpServer: (serverId: string, scope?: string) => void; + onDiscoverMcpTools: (serverId: string, scope?: string) => void; + onOpenCodexMcpForm: (server?: McpServer) => void; + onDeleteCodexMcpServer: (serverId: string) => void; +}; + +export type AgentCategoryTabsSectionProps = { + selectedCategory: AgentCategory; + onSelectCategory: (category: AgentCategory) => void; +}; + +export type AgentSelectorSectionProps = { + selectedAgent: AgentProvider; + onSelectAgent: (agent: AgentProvider) => void; + agentContextById: AgentContextByProvider; +}; + +export type AgentCategoryContentSectionProps = { + selectedAgent: AgentProvider; + selectedCategory: AgentCategory; + agentContextById: AgentContextByProvider; + claudePermissions: ClaudePermissionsState; + onClaudePermissionsChange: (value: ClaudePermissionsState) => void; + cursorPermissions: CursorPermissionsState; + onCursorPermissionsChange: (value: CursorPermissionsState) => void; + codexPermissionMode: CodexPermissionMode; + onCodexPermissionModeChange: (value: CodexPermissionMode) => void; + mcpServers: McpServer[]; + cursorMcpServers: McpServer[]; + codexMcpServers: McpServer[]; + mcpTestResults: Record; + mcpServerTools: Record; + mcpToolsLoading: Record; + onOpenMcpForm: (server?: McpServer) => void; + onDeleteMcpServer: (serverId: string, scope?: string) => void; + onTestMcpServer: (serverId: string, scope?: string) => void; + onDiscoverMcpTools: (serverId: string, scope?: string) => void; + onOpenCodexMcpForm: (server?: McpServer) => void; + onDeleteCodexMcpServer: (serverId: string) => void; +};