Implement SSH last connection management and enhance IPC handlers
- Added functionality to save and retrieve the last SSH connection configuration, allowing for auto-fill on subsequent launches. - Introduced new IPC channels for saving and getting the last SSH connection details. - Updated the connection state management to persist the last connection information upon successful connection. - Enhanced the ConnectionSection component to load the last connection details on mount and pre-fill the form fields. - Refactored relevant types and state management to accommodate the new SSH last connection features.
This commit is contained in:
parent
8a671bc53f
commit
ad4e75b8e5
10 changed files with 183 additions and 7 deletions
|
|
@ -23,7 +23,11 @@ import { createLogger } from '@shared/utils/logger';
|
||||||
import { app, BrowserWindow } from 'electron';
|
import { app, BrowserWindow } from 'electron';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
|
|
||||||
import { initializeIpcHandlers, removeIpcHandlers } from './ipc/handlers';
|
import {
|
||||||
|
initializeIpcHandlers,
|
||||||
|
reinitializeServiceHandlers,
|
||||||
|
removeIpcHandlers,
|
||||||
|
} from './ipc/handlers';
|
||||||
|
|
||||||
// Icon path - works for both dev and production
|
// Icon path - works for both dev and production
|
||||||
const getIconPath = (): string => {
|
const getIconPath = (): string => {
|
||||||
|
|
@ -108,6 +112,15 @@ function initializeServices(): void {
|
||||||
sessionParser = new SessionParser(projectScanner);
|
sessionParser = new SessionParser(projectScanner);
|
||||||
subagentResolver = new SubagentResolver(projectScanner);
|
subagentResolver = new SubagentResolver(projectScanner);
|
||||||
|
|
||||||
|
// Re-initialize IPC handler service references so subsequent calls use new instances
|
||||||
|
reinitializeServiceHandlers(
|
||||||
|
projectScanner,
|
||||||
|
sessionParser,
|
||||||
|
subagentResolver,
|
||||||
|
chunkBuilder,
|
||||||
|
dataCache
|
||||||
|
);
|
||||||
|
|
||||||
// Update file watcher provider
|
// Update file watcher provider
|
||||||
fileWatcher.setFileSystemProvider(provider);
|
fileWatcher.setFileSystemProvider(provider);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -95,6 +95,25 @@ export function initializeIpcHandlers(
|
||||||
logger.info('All handlers registered');
|
logger.info('All handlers registered');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Re-initializes service-dependent IPC handlers after a mode switch (local ↔ SSH).
|
||||||
|
* This updates the module-level service references held by each domain handler module,
|
||||||
|
* ensuring IPC calls after the switch use the new service instances.
|
||||||
|
*/
|
||||||
|
export function reinitializeServiceHandlers(
|
||||||
|
scanner: ProjectScanner,
|
||||||
|
parser: SessionParser,
|
||||||
|
resolver: SubagentResolver,
|
||||||
|
builder: ChunkBuilder,
|
||||||
|
cache: DataCache
|
||||||
|
): void {
|
||||||
|
initializeProjectHandlers(scanner);
|
||||||
|
initializeSessionHandlers(scanner, parser, resolver, builder, cache);
|
||||||
|
initializeSearchHandlers(scanner);
|
||||||
|
initializeSubagentHandlers(builder, cache, parser, resolver);
|
||||||
|
logger.info('Service handlers re-initialized after mode switch');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes all IPC handlers.
|
* Removes all IPC handlers.
|
||||||
* Should be called when shutting down.
|
* Should be called when shutting down.
|
||||||
|
|
|
||||||
|
|
@ -12,17 +12,22 @@ import {
|
||||||
SSH_CONNECT,
|
SSH_CONNECT,
|
||||||
SSH_DISCONNECT,
|
SSH_DISCONNECT,
|
||||||
SSH_GET_CONFIG_HOSTS,
|
SSH_GET_CONFIG_HOSTS,
|
||||||
|
SSH_GET_LAST_CONNECTION,
|
||||||
SSH_GET_STATE,
|
SSH_GET_STATE,
|
||||||
SSH_RESOLVE_HOST,
|
SSH_RESOLVE_HOST,
|
||||||
|
SSH_SAVE_LAST_CONNECTION,
|
||||||
SSH_TEST,
|
SSH_TEST,
|
||||||
} from '@preload/constants/ipcChannels';
|
} from '@preload/constants/ipcChannels';
|
||||||
import { createLogger } from '@shared/utils/logger';
|
import { createLogger } from '@shared/utils/logger';
|
||||||
|
|
||||||
|
import { configManager } from '../services';
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
SshConnectionConfig,
|
SshConnectionConfig,
|
||||||
SshConnectionManager,
|
SshConnectionManager,
|
||||||
SshConnectionStatus,
|
SshConnectionStatus,
|
||||||
} from '../services/infrastructure/SshConnectionManager';
|
} from '../services/infrastructure/SshConnectionManager';
|
||||||
|
import type { SshLastConnection } from '@shared/types';
|
||||||
import type { IpcMain } from 'electron';
|
import type { IpcMain } from 'electron';
|
||||||
|
|
||||||
const logger = createLogger('IPC:ssh');
|
const logger = createLogger('IPC:ssh');
|
||||||
|
|
@ -120,6 +125,36 @@ export function registerSshHandlers(ipcMain: IpcMain): void {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ipcMain.handle(SSH_SAVE_LAST_CONNECTION, async (_event, config: SshLastConnection) => {
|
||||||
|
try {
|
||||||
|
configManager.updateConfig('ssh', {
|
||||||
|
lastConnection: {
|
||||||
|
host: config.host,
|
||||||
|
port: config.port,
|
||||||
|
username: config.username,
|
||||||
|
authMethod: config.authMethod,
|
||||||
|
privateKeyPath: config.privateKeyPath,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return { success: true };
|
||||||
|
} catch (err) {
|
||||||
|
const message = err instanceof Error ? err.message : String(err);
|
||||||
|
logger.error('Failed to save SSH connection:', message);
|
||||||
|
return { success: false, error: message };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.handle(SSH_GET_LAST_CONNECTION, async () => {
|
||||||
|
try {
|
||||||
|
const config = configManager.getConfig();
|
||||||
|
return { success: true, data: config.ssh.lastConnection };
|
||||||
|
} catch (err) {
|
||||||
|
const message = err instanceof Error ? err.message : String(err);
|
||||||
|
logger.error('Failed to get last SSH connection:', message);
|
||||||
|
return { success: true, data: null };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
logger.info('SSH handlers registered');
|
logger.info('SSH handlers registered');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -130,4 +165,6 @@ export function removeSshHandlers(ipcMain: IpcMain): void {
|
||||||
ipcMain.removeHandler(SSH_TEST);
|
ipcMain.removeHandler(SSH_TEST);
|
||||||
ipcMain.removeHandler(SSH_GET_CONFIG_HOSTS);
|
ipcMain.removeHandler(SSH_GET_CONFIG_HOSTS);
|
||||||
ipcMain.removeHandler(SSH_RESOLVE_HOST);
|
ipcMain.removeHandler(SSH_RESOLVE_HOST);
|
||||||
|
ipcMain.removeHandler(SSH_SAVE_LAST_CONNECTION);
|
||||||
|
ipcMain.removeHandler(SSH_GET_LAST_CONNECTION);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -190,11 +190,23 @@ export interface SessionsConfig {
|
||||||
pinnedSessions: Record<string, { sessionId: string; pinnedAt: number }[]>;
|
pinnedSessions: Record<string, { sessionId: string; pinnedAt: number }[]>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface SshPersistConfig {
|
||||||
|
lastConnection: {
|
||||||
|
host: string;
|
||||||
|
port: number;
|
||||||
|
username: string;
|
||||||
|
authMethod: 'password' | 'privateKey' | 'agent' | 'auto';
|
||||||
|
privateKeyPath?: string;
|
||||||
|
} | null;
|
||||||
|
autoReconnect: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export interface AppConfig {
|
export interface AppConfig {
|
||||||
notifications: NotificationConfig;
|
notifications: NotificationConfig;
|
||||||
general: GeneralConfig;
|
general: GeneralConfig;
|
||||||
display: DisplayConfig;
|
display: DisplayConfig;
|
||||||
sessions: SessionsConfig;
|
sessions: SessionsConfig;
|
||||||
|
ssh: SshPersistConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Config section keys for type-safe updates
|
// Config section keys for type-safe updates
|
||||||
|
|
@ -232,6 +244,10 @@ const DEFAULT_CONFIG: AppConfig = {
|
||||||
sessions: {
|
sessions: {
|
||||||
pinnedSessions: {},
|
pinnedSessions: {},
|
||||||
},
|
},
|
||||||
|
ssh: {
|
||||||
|
lastConnection: null,
|
||||||
|
autoReconnect: false,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// ===========================================================================
|
// ===========================================================================
|
||||||
|
|
@ -352,6 +368,10 @@ export class ConfigManager {
|
||||||
...DEFAULT_CONFIG.sessions,
|
...DEFAULT_CONFIG.sessions,
|
||||||
...(loaded.sessions ?? {}),
|
...(loaded.sessions ?? {}),
|
||||||
},
|
},
|
||||||
|
ssh: {
|
||||||
|
...DEFAULT_CONFIG.ssh,
|
||||||
|
...(loaded.ssh ?? {}),
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -81,6 +81,12 @@ export const SSH_GET_CONFIG_HOSTS = 'ssh:getConfigHosts';
|
||||||
/** Resolve a single SSH config host alias */
|
/** Resolve a single SSH config host alias */
|
||||||
export const SSH_RESOLVE_HOST = 'ssh:resolveHost';
|
export const SSH_RESOLVE_HOST = 'ssh:resolveHost';
|
||||||
|
|
||||||
|
/** Save last SSH connection config */
|
||||||
|
export const SSH_SAVE_LAST_CONNECTION = 'ssh:saveLastConnection';
|
||||||
|
|
||||||
|
/** Get last saved SSH connection config */
|
||||||
|
export const SSH_GET_LAST_CONNECTION = 'ssh:getLastConnection';
|
||||||
|
|
||||||
/** SSH status event channel (main -> renderer) */
|
/** SSH status event channel (main -> renderer) */
|
||||||
export const SSH_STATUS = 'ssh:status';
|
export const SSH_STATUS = 'ssh:status';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,10 @@ import {
|
||||||
SSH_CONNECT,
|
SSH_CONNECT,
|
||||||
SSH_DISCONNECT,
|
SSH_DISCONNECT,
|
||||||
SSH_GET_CONFIG_HOSTS,
|
SSH_GET_CONFIG_HOSTS,
|
||||||
|
SSH_GET_LAST_CONNECTION,
|
||||||
SSH_GET_STATE,
|
SSH_GET_STATE,
|
||||||
SSH_RESOLVE_HOST,
|
SSH_RESOLVE_HOST,
|
||||||
|
SSH_SAVE_LAST_CONNECTION,
|
||||||
SSH_STATUS,
|
SSH_STATUS,
|
||||||
SSH_TEST,
|
SSH_TEST,
|
||||||
UPDATER_CHECK,
|
UPDATER_CHECK,
|
||||||
|
|
@ -42,6 +44,7 @@ import type {
|
||||||
SshConfigHostEntry,
|
SshConfigHostEntry,
|
||||||
SshConnectionConfig,
|
SshConnectionConfig,
|
||||||
SshConnectionStatus,
|
SshConnectionStatus,
|
||||||
|
SshLastConnection,
|
||||||
TriggerTestResult,
|
TriggerTestResult,
|
||||||
} from '@shared/types';
|
} from '@shared/types';
|
||||||
|
|
||||||
|
|
@ -341,6 +344,12 @@ const electronAPI: ElectronAPI = {
|
||||||
resolveHost: async (alias: string): Promise<SshConfigHostEntry | null> => {
|
resolveHost: async (alias: string): Promise<SshConfigHostEntry | null> => {
|
||||||
return invokeIpcWithResult<SshConfigHostEntry | null>(SSH_RESOLVE_HOST, alias);
|
return invokeIpcWithResult<SshConfigHostEntry | null>(SSH_RESOLVE_HOST, alias);
|
||||||
},
|
},
|
||||||
|
saveLastConnection: async (config: SshLastConnection): Promise<void> => {
|
||||||
|
return invokeIpcWithResult<void>(SSH_SAVE_LAST_CONNECTION, config);
|
||||||
|
},
|
||||||
|
getLastConnection: async (): Promise<SshLastConnection | null> => {
|
||||||
|
return invokeIpcWithResult<SshLastConnection | null>(SSH_GET_LAST_CONNECTION);
|
||||||
|
},
|
||||||
onStatus: (callback: (event: unknown, status: SshConnectionStatus) => void): (() => void) => {
|
onStatus: (callback: (event: unknown, status: SshConnectionStatus) => void): (() => void) => {
|
||||||
ipcRenderer.on(
|
ipcRenderer.on(
|
||||||
SSH_STATUS,
|
SSH_STATUS,
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,8 @@ export const ConnectionSection = (): React.JSX.Element => {
|
||||||
const testConnection = useStore((s) => s.testConnection);
|
const testConnection = useStore((s) => s.testConnection);
|
||||||
const sshConfigHosts = useStore((s) => s.sshConfigHosts);
|
const sshConfigHosts = useStore((s) => s.sshConfigHosts);
|
||||||
const fetchSshConfigHosts = useStore((s) => s.fetchSshConfigHosts);
|
const fetchSshConfigHosts = useStore((s) => s.fetchSshConfigHosts);
|
||||||
|
const lastSshConfig = useStore((s) => s.lastSshConfig);
|
||||||
|
const loadLastConnection = useStore((s) => s.loadLastConnection);
|
||||||
|
|
||||||
// Form state
|
// Form state
|
||||||
const [host, setHost] = useState('');
|
const [host, setHost] = useState('');
|
||||||
|
|
@ -43,10 +45,29 @@ export const ConnectionSection = (): React.JSX.Element => {
|
||||||
const hostInputRef = useRef<HTMLInputElement>(null);
|
const hostInputRef = useRef<HTMLInputElement>(null);
|
||||||
const dropdownRef = useRef<HTMLDivElement>(null);
|
const dropdownRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
// Fetch SSH config hosts on mount
|
// Fetch SSH config hosts and load last connection on mount
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
void fetchSshConfigHosts();
|
void fetchSshConfigHosts();
|
||||||
}, [fetchSshConfigHosts]);
|
void loadLastConnection();
|
||||||
|
}, [fetchSshConfigHosts, loadLastConnection]);
|
||||||
|
|
||||||
|
// Pre-fill form from saved connection config when it arrives (one-time on mount).
|
||||||
|
// setState in effect is intentional: lastSshConfig loads async from IPC, so we can't
|
||||||
|
// use it as useState initializers.
|
||||||
|
const prefilled = useRef(false);
|
||||||
|
useEffect(() => {
|
||||||
|
if (lastSshConfig && connectionState !== 'connected' && !prefilled.current) {
|
||||||
|
prefilled.current = true;
|
||||||
|
setHost(lastSshConfig.host);
|
||||||
|
setPort(String(lastSshConfig.port));
|
||||||
|
setUsername(lastSshConfig.username);
|
||||||
|
setAuthMethod(lastSshConfig.authMethod);
|
||||||
|
if (lastSshConfig.privateKeyPath) {
|
||||||
|
setPrivateKeyPath(lastSshConfig.privateKeyPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps -- one-time prefill when async data arrives
|
||||||
|
}, [lastSshConfig]);
|
||||||
|
|
||||||
// Close dropdown on outside click
|
// Close dropdown on outside click
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
|
||||||
|
|
@ -288,9 +288,11 @@ export function initializeNotificationListeners(): () => void {
|
||||||
s.error
|
s.error
|
||||||
);
|
);
|
||||||
|
|
||||||
// Re-fetch data when connection state changes to connected or disconnected
|
// Re-fetch all data when connection state changes to connected or disconnected
|
||||||
if (s.state === 'connected' || s.state === 'disconnected') {
|
if (s.state === 'connected' || s.state === 'disconnected') {
|
||||||
void useStore.getState().fetchProjects();
|
const store = useStore.getState();
|
||||||
|
void store.fetchProjects();
|
||||||
|
void store.fetchRepositoryGroups();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (typeof cleanup === 'function') {
|
if (typeof cleanup === 'function') {
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,15 @@
|
||||||
* and provides actions for connecting/disconnecting.
|
* and provides actions for connecting/disconnecting.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { getFullResetState } from '../utils/stateResetHelpers';
|
||||||
|
|
||||||
import type { AppState } from '../types';
|
import type { AppState } from '../types';
|
||||||
import type { SshConfigHostEntry, SshConnectionConfig, SshConnectionState } from '@shared/types';
|
import type {
|
||||||
|
SshConfigHostEntry,
|
||||||
|
SshConnectionConfig,
|
||||||
|
SshConnectionState,
|
||||||
|
SshLastConnection,
|
||||||
|
} from '@shared/types';
|
||||||
import type { StateCreator } from 'zustand';
|
import type { StateCreator } from 'zustand';
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
@ -20,6 +27,7 @@ export interface ConnectionSlice {
|
||||||
connectedHost: string | null;
|
connectedHost: string | null;
|
||||||
connectionError: string | null;
|
connectionError: string | null;
|
||||||
sshConfigHosts: SshConfigHostEntry[];
|
sshConfigHosts: SshConfigHostEntry[];
|
||||||
|
lastSshConfig: SshLastConnection | null;
|
||||||
|
|
||||||
// Actions
|
// Actions
|
||||||
connectSsh: (config: SshConnectionConfig) => Promise<void>;
|
connectSsh: (config: SshConnectionConfig) => Promise<void>;
|
||||||
|
|
@ -32,6 +40,7 @@ export interface ConnectionSlice {
|
||||||
) => void;
|
) => void;
|
||||||
fetchSshConfigHosts: () => Promise<void>;
|
fetchSshConfigHosts: () => Promise<void>;
|
||||||
resolveConfigHost: (alias: string) => Promise<SshConfigHostEntry | null>;
|
resolveConfigHost: (alias: string) => Promise<SshConfigHostEntry | null>;
|
||||||
|
loadLastConnection: () => Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
@ -48,6 +57,7 @@ export const createConnectionSlice: StateCreator<AppState, [], [], ConnectionSli
|
||||||
connectedHost: null,
|
connectedHost: null,
|
||||||
connectionError: null,
|
connectionError: null,
|
||||||
sshConfigHosts: [],
|
sshConfigHosts: [],
|
||||||
|
lastSshConfig: null,
|
||||||
|
|
||||||
// Actions
|
// Actions
|
||||||
connectSsh: async (config: SshConnectionConfig): Promise<void> => {
|
connectSsh: async (config: SshConnectionConfig): Promise<void> => {
|
||||||
|
|
@ -64,12 +74,26 @@ export const createConnectionSlice: StateCreator<AppState, [], [], ConnectionSli
|
||||||
connectionState: status.state,
|
connectionState: status.state,
|
||||||
connectedHost: status.host,
|
connectedHost: status.host,
|
||||||
connectionError: status.error,
|
connectionError: status.error,
|
||||||
|
// Clear stale local selections so dashboard shows fresh remote data
|
||||||
|
...(status.state === 'connected' ? getFullResetState() : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Re-fetch all data when connected
|
// Re-fetch all data and persist config when connected
|
||||||
if (status.state === 'connected') {
|
if (status.state === 'connected') {
|
||||||
const state = get();
|
const state = get();
|
||||||
void state.fetchProjects();
|
void state.fetchProjects();
|
||||||
|
void state.fetchRepositoryGroups();
|
||||||
|
|
||||||
|
// Save connection config (without password) for form pre-fill on next launch
|
||||||
|
const saved: SshLastConnection = {
|
||||||
|
host: config.host,
|
||||||
|
port: config.port,
|
||||||
|
username: config.username,
|
||||||
|
authMethod: config.authMethod,
|
||||||
|
privateKeyPath: config.privateKeyPath,
|
||||||
|
};
|
||||||
|
set({ lastSshConfig: saved });
|
||||||
|
void window.electronAPI.ssh.saveLastConnection(saved);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
const message = err instanceof Error ? err.message : String(err);
|
const message = err instanceof Error ? err.message : String(err);
|
||||||
|
|
@ -88,11 +112,14 @@ export const createConnectionSlice: StateCreator<AppState, [], [], ConnectionSli
|
||||||
connectionState: status.state,
|
connectionState: status.state,
|
||||||
connectedHost: null,
|
connectedHost: null,
|
||||||
connectionError: null,
|
connectionError: null,
|
||||||
|
// Clear stale remote selections so dashboard shows fresh local data
|
||||||
|
...getFullResetState(),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Re-fetch local data
|
// Re-fetch local data
|
||||||
const state = get();
|
const state = get();
|
||||||
void state.fetchProjects();
|
void state.fetchProjects();
|
||||||
|
void state.fetchRepositoryGroups();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
const message = err instanceof Error ? err.message : String(err);
|
const message = err instanceof Error ? err.message : String(err);
|
||||||
set({ connectionError: message });
|
set({ connectionError: message });
|
||||||
|
|
@ -140,4 +167,13 @@ export const createConnectionSlice: StateCreator<AppState, [], [], ConnectionSli
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
loadLastConnection: async (): Promise<void> => {
|
||||||
|
try {
|
||||||
|
const saved = await window.electronAPI.ssh.getLastConnection();
|
||||||
|
set({ lastSshConfig: saved });
|
||||||
|
} catch {
|
||||||
|
// Gracefully ignore - no saved connection
|
||||||
|
}
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -207,6 +207,17 @@ export interface SshConnectionStatus {
|
||||||
/**
|
/**
|
||||||
* SSH API exposed via preload.
|
* SSH API exposed via preload.
|
||||||
*/
|
*/
|
||||||
|
/**
|
||||||
|
* Saved SSH connection config (no password).
|
||||||
|
*/
|
||||||
|
export interface SshLastConnection {
|
||||||
|
host: string;
|
||||||
|
port: number;
|
||||||
|
username: string;
|
||||||
|
authMethod: SshAuthMethod;
|
||||||
|
privateKeyPath?: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface SshAPI {
|
export interface SshAPI {
|
||||||
connect: (config: SshConnectionConfig) => Promise<SshConnectionStatus>;
|
connect: (config: SshConnectionConfig) => Promise<SshConnectionStatus>;
|
||||||
disconnect: () => Promise<SshConnectionStatus>;
|
disconnect: () => Promise<SshConnectionStatus>;
|
||||||
|
|
@ -214,6 +225,8 @@ export interface SshAPI {
|
||||||
test: (config: SshConnectionConfig) => Promise<{ success: boolean; error?: string }>;
|
test: (config: SshConnectionConfig) => Promise<{ success: boolean; error?: string }>;
|
||||||
getConfigHosts: () => Promise<SshConfigHostEntry[]>;
|
getConfigHosts: () => Promise<SshConfigHostEntry[]>;
|
||||||
resolveHost: (alias: string) => Promise<SshConfigHostEntry | null>;
|
resolveHost: (alias: string) => Promise<SshConfigHostEntry | null>;
|
||||||
|
saveLastConnection: (config: SshLastConnection) => Promise<void>;
|
||||||
|
getLastConnection: () => Promise<SshLastConnection | null>;
|
||||||
onStatus: (callback: (event: unknown, status: SshConnectionStatus) => void) => () => void;
|
onStatus: (callback: (event: unknown, status: SshConnectionStatus) => void) => () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue