diff --git a/frontend/components/connections/QuickConnect.vue b/frontend/components/connections/QuickConnect.vue new file mode 100644 index 0000000..8c453cb --- /dev/null +++ b/frontend/components/connections/QuickConnect.vue @@ -0,0 +1,46 @@ + + + + + + SSH + RDP + + + Connect + + diff --git a/frontend/pages/index.vue b/frontend/pages/index.vue index 8ac1260..3b8a719 100644 --- a/frontend/pages/index.vue +++ b/frontend/pages/index.vue @@ -2,9 +2,13 @@ import { useTerminal } from '~/composables/useTerminal' const connections = useConnectionStore() +const sessions = useSessionStore() const showHostDialog = ref(false) const editingHost = ref(null) const showGroupDialog = ref(false) +const searchQuery = ref('') +const showSavePrompt = ref(false) +const pendingQuickConnect = ref(null) // Terminal composable for connect-on-click const { createTerminal, connectToHost } = useTerminal() @@ -25,15 +29,9 @@ function openEditHost(host: any) { function connectHost(host: any) { if (host.protocol !== 'ssh') { - // RDP support in Phase 3 + // RDP handled via quick connect for now return } - // We connect via useTerminal — TerminalInstance will handle the actual mount - // Here we just trigger SessionContainer to render a new TerminalInstance - // The terminal composable is invoked inside TerminalInstance on mount - // We signal the session store directly to open a pending session slot - // TerminalInstance picks up the hostId prop and opens the WS connection - const sessions = useSessionStore() const pendingId = `pending-${Date.now()}` sessions.addSession({ id: pendingId, @@ -44,38 +42,155 @@ function connectHost(host: any) { active: true, }) } + +// Quick connect: launch a temporary session without saving +function handleQuickConnect(params: { hostname: string; port: number; username: string; protocol: 'ssh' | 'rdp' }) { + const sessionId = `quick-${Date.now()}` + const displayName = params.username + ? `${params.username}@${params.hostname}` + : params.hostname + + sessions.addSession({ + id: sessionId, + hostId: null, + hostName: displayName, + hostname: params.hostname, + port: params.port, + username: params.username, + protocol: params.protocol, + color: null, + active: true, + isTemporary: true, + }) + + pendingQuickConnect.value = params + showSavePrompt.value = true +} + +// Save a quick-connect as a permanent host +function saveQuickConnectHost() { + if (!pendingQuickConnect.value) return + const p = pendingQuickConnect.value + editingHost.value = { + hostname: p.hostname, + port: p.port, + protocol: p.protocol, + name: p.hostname, + } + showSavePrompt.value = false + pendingQuickConnect.value = null + showHostDialog.value = true +} + +function dismissSavePrompt() { + showSavePrompt.value = false + pendingQuickConnect.value = null +} + +// Client-side search filtering +const filteredHosts = computed(() => { + if (!searchQuery.value.trim()) return connections.hosts + const q = searchQuery.value.toLowerCase() + return connections.hosts.filter((h: any) => + h.name?.toLowerCase().includes(q) || + h.hostname?.toLowerCase().includes(q) || + (h.tags || []).some((t: string) => t.toLowerCase().includes(q)) + ) +}) + +// Recent connections — hosts sorted by lastConnectedAt, non-null only, top 5 +const recentHosts = computed(() => { + return [...connections.hosts] + .filter((h: any) => h.lastConnectedAt) + .sort((a: any, b: any) => + new Date(b.lastConnectedAt).getTime() - new Date(a.lastConnectedAt).getTime() + ) + .slice(0, 5) +}) - - - + + + - - - - - - - No hosts yet. Click "+ Host" to add your first connection. - - + + + Save this connection for later? + Save + Dismiss + + + + + + + + + + + + + + + + Recent + + + + + {{ host.name }} + {{ host.hostname }} + + + + + + + + + All Hosts + + + + + + No hosts match "{{ searchQuery }}" + + + No hosts yet. Click "+ Host" to add your first connection. + + + +
- No hosts yet. Click "+ Host" to add your first connection. -
{{ host.name }}
{{ host.hostname }}
+ No hosts match "{{ searchQuery }}" +
+ No hosts yet. Click "+ Host" to add your first connection. +