diff --git a/src/main/services/infrastructure/ServiceContext.ts b/src/main/services/infrastructure/ServiceContext.ts index eefef501..f5be5a66 100644 --- a/src/main/services/infrastructure/ServiceContext.ts +++ b/src/main/services/infrastructure/ServiceContext.ts @@ -13,8 +13,8 @@ import { ChunkBuilder } from '@main/services/analysis/ChunkBuilder'; import { ProjectScanner } from '@main/services/discovery/ProjectScanner'; -import { SessionParser } from '@main/services/parsing/SessionParser'; import { SubagentResolver } from '@main/services/discovery/SubagentResolver'; +import { SessionParser } from '@main/services/parsing/SessionParser'; import { CACHE_CLEANUP_INTERVAL_MINUTES, CACHE_TTL_MINUTES, diff --git a/src/main/services/infrastructure/ServiceContextRegistry.ts b/src/main/services/infrastructure/ServiceContextRegistry.ts index 4ae1e79a..1d18715d 100644 --- a/src/main/services/infrastructure/ServiceContextRegistry.ts +++ b/src/main/services/infrastructure/ServiceContextRegistry.ts @@ -18,7 +18,7 @@ import { createLogger } from '@shared/utils/logger'; -import { ServiceContext } from './ServiceContext'; +import { type ServiceContext } from './ServiceContext'; const logger = createLogger('Infrastructure:ServiceContextRegistry'); @@ -161,7 +161,7 @@ export class ServiceContextRegistry { * Lists all registered contexts. * @returns Array of context metadata */ - list(): Array<{ id: string; type: 'local' | 'ssh' }> { + list(): { id: string; type: 'local' | 'ssh' }[] { return Array.from(this.contexts.values()).map((context) => ({ id: context.id, type: context.type, diff --git a/src/renderer/components/common/ContextSwitcher.tsx b/src/renderer/components/common/WorkspaceIndicator.tsx similarity index 80% rename from src/renderer/components/common/ContextSwitcher.tsx rename to src/renderer/components/common/WorkspaceIndicator.tsx index f58c5e3e..fbd70624 100644 --- a/src/renderer/components/common/ContextSwitcher.tsx +++ b/src/renderer/components/common/WorkspaceIndicator.tsx @@ -1,8 +1,9 @@ /** - * ContextSwitcher - Workspace context dropdown in SidebarHeader. + * WorkspaceIndicator - Floating bottom-right pill badge for workspace switching. * - * Displays active context (Local or SSH host) with connection status badge. - * Dropdown lists all available contexts with click-to-switch functionality. + * Shows active workspace (Local or SSH host) with connection status badge. + * Clicking opens an upward dropdown to switch between available workspaces. + * Only renders when multiple contexts are available (hidden in local-only mode). */ import { useEffect, useRef, useState } from 'react'; @@ -13,7 +14,7 @@ import { useShallow } from 'zustand/react/shallow'; import { ConnectionStatusBadge } from './ConnectionStatusBadge'; -export const ContextSwitcher = (): React.JSX.Element => { +export const WorkspaceIndicator = (): React.JSX.Element | null => { const { activeContextId, isContextSwitching, availableContexts, switchContext } = useStore( useShallow((s) => ({ activeContextId: s.activeContextId, @@ -48,25 +49,27 @@ export const ContextSwitcher = (): React.JSX.Element => { return () => document.removeEventListener('keydown', handleEscape); }, []); - // Get display label for context + // Only show when multiple contexts exist + if (availableContexts.length <= 1) return null; + const getContextLabel = (contextId: string): string => { - if (contextId === 'local') { - return 'Local'; - } - // Strip 'ssh-' prefix for display (e.g., 'ssh-192.168.1.10' -> '192.168.1.10') + if (contextId === 'local') return 'Local'; return contextId.startsWith('ssh-') ? contextId.slice(4) : contextId; }; const activeLabel = getContextLabel(activeContextId); return ( -
- {/* Trigger button */} +
+ {/* Trigger pill */} - {/* Dropdown panel */} + {/* Upward dropdown */} {isOpen && !isContextSwitching && ( <> - {/* Backdrop overlay */} + {/* Backdrop */}
setIsOpen(false)} /> - {/* Dropdown content */} + {/* Dropdown content - opens upward */}
{ } as React.CSSProperties } > - {/* Context Switcher - workspace indicator */} - - - {/* Visual separator */} -
- {/* Project name dropdown button */} + {isOpen && ( +
+ {authMethodOptions.map((opt) => ( + + ))} +
+ )} +
+
+ ); +}; + export const WorkspaceSection = (): React.JSX.Element => { const [profiles, setProfiles] = useState([]); const [loading, setLoading] = useState(true); @@ -212,22 +314,7 @@ export const WorkspaceSection = (): React.JSX.Element => {
-
- - -
+ {formAuthMethod === 'privateKey' && (
@@ -245,6 +332,12 @@ export const WorkspaceSection = (): React.JSX.Element => {
)} + {formAuthMethod === 'password' && ( +

+ You will be prompted for the password when connecting. +

+ )} +