diff --git a/src/renderer/components/extensions/ExtensionStoreView.tsx b/src/renderer/components/extensions/ExtensionStoreView.tsx index 4928deb4..d1ad148e 100644 --- a/src/renderer/components/extensions/ExtensionStoreView.tsx +++ b/src/renderer/components/extensions/ExtensionStoreView.tsx @@ -194,7 +194,7 @@ export const ExtensionStoreView = (): React.JSX.Element => { variant="outline" size="sm" onClick={() => setCustomMcpDialogOpen(true)} - className="whitespace-nowrap" + className="mb-1 whitespace-nowrap" > Add Custom diff --git a/src/renderer/components/extensions/common/InstallButton.tsx b/src/renderer/components/extensions/common/InstallButton.tsx index ba65ae09..cab9ae13 100644 --- a/src/renderer/components/extensions/common/InstallButton.tsx +++ b/src/renderer/components/extensions/common/InstallButton.tsx @@ -3,6 +3,8 @@ * States: idle → pending (spinner) → success (checkmark, 2s) → idle */ +import { useEffect, useState } from 'react'; + import { Check, Loader2, Trash2 } from 'lucide-react'; import { Button } from '@renderer/components/ui/button'; @@ -38,11 +40,22 @@ export function InstallButton({ const cliStatus = useStore((s) => s.cliStatus); const cliMissing = cliStatus !== null && !cliStatus.installed; const isDisabled = disabled || cliMissing; + const [lastAction, setLastAction] = useState<'install' | 'uninstall' | null>(null); + + useEffect(() => { + if (state === 'idle' || state === 'success') { + setLastAction(null); + } + }, [state]); + + const pendingAction = lastAction ?? (isInstalled ? 'uninstall' : 'install'); if (state === 'pending') { return ( ); } @@ -64,7 +77,14 @@ export function InstallButton({ className="border-red-500/30 text-red-400 hover:bg-red-500/10" onClick={(e) => { e.stopPropagation(); - (isInstalled ? onUninstall : onInstall)(); + if (pendingAction === 'uninstall') { + setLastAction('uninstall'); + onUninstall(); + return; + } + + setLastAction('install'); + onInstall(); }} disabled={isDisabled} > @@ -96,6 +116,7 @@ export function InstallButton({ className="border-red-500/30 text-red-400 hover:bg-red-500/10" onClick={(e) => { e.stopPropagation(); + setLastAction('uninstall'); onUninstall(); }} disabled={isDisabled} @@ -109,6 +130,7 @@ export function InstallButton({ variant="default" onClick={(e) => { e.stopPropagation(); + setLastAction('install'); onInstall(); }} disabled={isDisabled} diff --git a/src/renderer/components/extensions/mcp/McpServersPanel.tsx b/src/renderer/components/extensions/mcp/McpServersPanel.tsx index ef0bf85f..e2131fc5 100644 --- a/src/renderer/components/extensions/mcp/McpServersPanel.tsx +++ b/src/renderer/components/extensions/mcp/McpServersPanel.tsx @@ -6,8 +6,6 @@ import { useEffect, useMemo, useState } from 'react'; import { Badge } from '@renderer/components/ui/badge'; import { Button } from '@renderer/components/ui/button'; -import { Checkbox } from '@renderer/components/ui/checkbox'; -import { Label } from '@renderer/components/ui/label'; import { Select, SelectContent, @@ -87,7 +85,6 @@ export const McpServersPanel = ({ const runMcpDiagnostics = useStore((s) => s.runMcpDiagnostics); const [mcpSort, setMcpSort] = useState('name-asc'); - const [mcpInstalledOnly, setMcpInstalledOnly] = useState(false); // Load initial browse data useEffect(() => { @@ -155,14 +152,8 @@ export const McpServersPanel = ({ } }; - // Sort + filter - const displayServers = useMemo(() => { - let result = rawServers; - if (mcpInstalledOnly) { - result = result.filter(isServerInstalled); - } - return sortMcpServers(result, mcpSort); - }, [rawServers, mcpSort, mcpInstalledOnly, installedNames]); + // Sort displayed servers + const displayServers = useMemo(() => sortMcpServers(rawServers, mcpSort), [rawServers, mcpSort]); // Find selected server (search in both lists to avoid losing selection during search toggle) const selectedServer = useMemo(() => { @@ -219,7 +210,7 @@ export const McpServersPanel = ({ )} {allDiagnostics.length > 0 ? ( -
+
{allDiagnostics.map((diagnostic) => (
- {/* Search + Sort + Installed only row */} + {/* Search + sort row */}
-
- setMcpInstalledOnly(!mcpInstalledOnly)} - /> - -
{/* Warnings */} @@ -343,31 +321,23 @@ export const McpServersPanel = ({ {!isLoading && displayServers.length === 0 && (
- {isSearching || mcpInstalledOnly ? ( + {isSearching ? ( ) : ( )}

- {isSearching - ? 'No servers found' - : mcpInstalledOnly - ? 'No installed servers' - : 'No MCP servers available'} + {isSearching ? 'No servers found' : 'No MCP servers available'}

- {isSearching - ? 'Try a different search term' - : mcpInstalledOnly - ? 'Install servers from the catalog to see them here' - : 'Check back later for new servers'} + {isSearching ? 'Try a different search term' : 'Check back later for new servers'}

)} {displayServers.length > 0 && ( -
+
{displayServers.map((server) => ( +
{ALL_CAPABILITIES.map((cap) => { const count = capabilityCounts.get(cap) ?? 0; if (count === 0) return null; @@ -46,7 +46,7 @@ export const CapabilityChips = ({ size="sm" onClick={() => onToggle(cap)} aria-pressed={isActive} - className={`h-8 rounded-full border px-3 text-xs font-medium transition-all ${ + className={`h-7 rounded-full border px-2.5 text-[11px] font-medium transition-all ${ isActive ? 'border-purple-500/40 bg-purple-500/15 text-purple-300 shadow-sm' : 'hover:bg-surface-raised/60 border-border bg-transparent text-text-secondary hover:border-border-emphasis hover:text-text' @@ -54,7 +54,7 @@ export const CapabilityChips = ({ > {getCapabilityLabel(cap)} ; return ( -
+
{categoryCounts.map(([category, count]) => { const isActive = selected.includes(category); return ( @@ -43,7 +43,7 @@ export const CategoryChips = ({ size="sm" onClick={() => onToggle(category)} aria-pressed={isActive} - className={`h-8 rounded-full border px-3 text-xs font-medium transition-all ${ + className={`h-7 rounded-full border px-2.5 text-[11px] font-medium transition-all ${ isActive ? 'border-blue-500/40 bg-blue-500/15 text-blue-300 shadow-sm' : 'hover:bg-surface-raised/60 border-border bg-transparent text-text-secondary hover:border-border-emphasis hover:text-text' @@ -51,7 +51,7 @@ export const CategoryChips = ({ > {category} - + + @@ -246,38 +247,40 @@ export const PluginsPanel = ({ )}
-
-
-
- - Categories - - - {pluginFilters.categories.length} selected - -
- -
+
+
+
+
+ + Categories + + + {pluginFilters.categories.length} selected + +
+ +
-
-
- - Capabilities - - - {pluginFilters.capabilities.length} selected - -
- -
+
+
+ + Capabilities + + + {pluginFilters.capabilities.length} selected + +
+ +
+
@@ -358,7 +361,7 @@ export const PluginsPanel = ({ )} {!loading && !error && filtered.length > 0 && ( -
+
{filtered.map((plugin, index) => (
-
+
{visibleProjectSkills.map((skill) => (
-
+
{visibleUserSkills.map((skill) => (