[Init] Initial commit - NetMesh terminal manager
Some checks failed
build-packages / resolve bundled mosh-client (push) Has been cancelled
build-packages / resolve bundled et-client (push) Has been cancelled
build-packages / build-macos (push) Has been cancelled
build-packages / build-windows (push) Has been cancelled
build-packages / build-linux-x64 (push) Has been cancelled
build-packages / build-linux-arm64 (push) Has been cancelled
build-packages / release (push) Has been cancelled
build-packages / update Nix release metadata (push) Has been cancelled
build-packages / bump homebrew tap (push) Has been cancelled
test / lint-and-test (push) Has been cancelled
AI automation / Route event (push) Has been cancelled
AI automation / Hand reopened issue to maintainers (push) Has been cancelled
AI automation / Clean source issue state (push) Has been cancelled
AI automation / Reconcile handoffs (push) Has been cancelled
AI automation / Classify issue (push) Has been cancelled
AI automation / Claude Code smoke (push) Has been cancelled
AI automation / Review issue follow-up (push) Has been cancelled
AI automation / Publish issue follow-up (push) Has been cancelled
AI automation / Implement with Claude Code (push) Has been cancelled
AI automation / Publish implement PR (push) Has been cancelled
AI automation / Continue queued issue comments (push) Has been cancelled
AI automation / Codex review loop (push) Has been cancelled
AI automation / Publish Codex fix (push) Has been cancelled
AI automation / Clear Codex dispatch marker (push) Has been cancelled
AI automation / Own PR re-request Codex (push) Has been cancelled
AI automation / External PR re-request Codex (push) Has been cancelled
AI automation / Poll Codex reaction / retry (push) Has been cancelled
build-et-binaries / build-linux-x64 (push) Has been cancelled
build-et-binaries / build-linux-arm64 (push) Has been cancelled
build-et-binaries / build-macos-universal (push) Has been cancelled
build-et-binaries / build-windows-x64 (push) Has been cancelled
build-et-binaries / release (push) Has been cancelled
Some checks failed
build-packages / resolve bundled mosh-client (push) Has been cancelled
build-packages / resolve bundled et-client (push) Has been cancelled
build-packages / build-macos (push) Has been cancelled
build-packages / build-windows (push) Has been cancelled
build-packages / build-linux-x64 (push) Has been cancelled
build-packages / build-linux-arm64 (push) Has been cancelled
build-packages / release (push) Has been cancelled
build-packages / update Nix release metadata (push) Has been cancelled
build-packages / bump homebrew tap (push) Has been cancelled
test / lint-and-test (push) Has been cancelled
AI automation / Route event (push) Has been cancelled
AI automation / Hand reopened issue to maintainers (push) Has been cancelled
AI automation / Clean source issue state (push) Has been cancelled
AI automation / Reconcile handoffs (push) Has been cancelled
AI automation / Classify issue (push) Has been cancelled
AI automation / Claude Code smoke (push) Has been cancelled
AI automation / Review issue follow-up (push) Has been cancelled
AI automation / Publish issue follow-up (push) Has been cancelled
AI automation / Implement with Claude Code (push) Has been cancelled
AI automation / Publish implement PR (push) Has been cancelled
AI automation / Continue queued issue comments (push) Has been cancelled
AI automation / Codex review loop (push) Has been cancelled
AI automation / Publish Codex fix (push) Has been cancelled
AI automation / Clear Codex dispatch marker (push) Has been cancelled
AI automation / Own PR re-request Codex (push) Has been cancelled
AI automation / External PR re-request Codex (push) Has been cancelled
AI automation / Poll Codex reaction / retry (push) Has been cancelled
build-et-binaries / build-linux-x64 (push) Has been cancelled
build-et-binaries / build-linux-arm64 (push) Has been cancelled
build-et-binaries / build-macos-universal (push) Has been cancelled
build-et-binaries / build-windows-x64 (push) Has been cancelled
build-et-binaries / release (push) Has been cancelled
This commit is contained in:
99
application/state/sftp/useSftpSessionErrors.ts
Normal file
99
application/state/sftp/useSftpSessionErrors.ts
Normal file
@@ -0,0 +1,99 @@
|
||||
import { useCallback } from "react";
|
||||
import type { MutableRefObject } from "react";
|
||||
import type { Host } from "../../../domain/models";
|
||||
import type { SftpPane } from "./types";
|
||||
|
||||
interface UseSftpSessionErrorsParams {
|
||||
getActivePane: (side: "left" | "right") => SftpPane | null;
|
||||
leftTabsRef: MutableRefObject<{ tabs: SftpPane[]; activeTabId: string | null }>;
|
||||
rightTabsRef: MutableRefObject<{ tabs: SftpPane[]; activeTabId: string | null }>;
|
||||
updateActiveTab: (
|
||||
side: "left" | "right",
|
||||
updater: (prev: SftpPane) => SftpPane,
|
||||
) => void;
|
||||
navSeqRef: MutableRefObject<{ left: number; right: number }>;
|
||||
lastConnectedHostRef: MutableRefObject<{ left: Host | "local" | null; right: Host | "local" | null }>;
|
||||
releaseConnection: (connectionId: string) => Promise<void>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether we still know enough to reconnect after a session drop.
|
||||
* Prefer reconnect over wiping the pane to the empty "select host" screen —
|
||||
* that wipe was especially easy to hit when listing "/" failed/timed out on
|
||||
* some hosts while the file list was empty or lastHost had raced away.
|
||||
*/
|
||||
export function canReconnectSftpPane(params: {
|
||||
lastHost: Host | "local" | null;
|
||||
connection: SftpPane["connection"];
|
||||
}): boolean {
|
||||
const { lastHost, connection } = params;
|
||||
if (lastHost && lastHost !== "local") return true;
|
||||
if (lastHost === "local") return true;
|
||||
if (connection && !connection.isLocal && !!connection.hostId) return true;
|
||||
if (connection?.isLocal) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
export const useSftpSessionErrors = ({
|
||||
getActivePane,
|
||||
leftTabsRef,
|
||||
rightTabsRef,
|
||||
updateActiveTab,
|
||||
navSeqRef,
|
||||
lastConnectedHostRef,
|
||||
releaseConnection,
|
||||
}: UseSftpSessionErrorsParams) =>
|
||||
useCallback(
|
||||
(side: "left" | "right", _error: Error) => {
|
||||
const pane = getActivePane(side);
|
||||
const sideTabs = side === "left" ? leftTabsRef.current : rightTabsRef.current;
|
||||
|
||||
if (!pane || !sideTabs.activeTabId) return;
|
||||
|
||||
if (pane.connection) {
|
||||
void releaseConnection(pane.connection.id);
|
||||
}
|
||||
|
||||
navSeqRef.current[side] += 1;
|
||||
|
||||
const lastHost = lastConnectedHostRef.current[side];
|
||||
const canReconnect = canReconnectSftpPane({
|
||||
lastHost,
|
||||
connection: pane.connection,
|
||||
});
|
||||
|
||||
if (canReconnect) {
|
||||
// Keep the connection object (host identity + path) so the UI does not
|
||||
// collapse into the empty host picker when listing root (or any path)
|
||||
// fails with a transient session error on some servers.
|
||||
updateActiveTab(side, (prev) => ({
|
||||
...prev,
|
||||
reconnecting: true,
|
||||
loading: false,
|
||||
error: "sftp.error.connectionLostReconnecting",
|
||||
}));
|
||||
return;
|
||||
}
|
||||
|
||||
// No host identity left — fall back to empty picker.
|
||||
updateActiveTab(side, (prev) => ({
|
||||
...prev,
|
||||
connection: null,
|
||||
files: [],
|
||||
loading: false,
|
||||
reconnecting: false,
|
||||
error: "sftp.error.sessionLost",
|
||||
selectedFiles: new Set(),
|
||||
filter: "",
|
||||
}));
|
||||
},
|
||||
[
|
||||
getActivePane,
|
||||
leftTabsRef,
|
||||
rightTabsRef,
|
||||
updateActiveTab,
|
||||
navSeqRef,
|
||||
lastConnectedHostRef,
|
||||
releaseConnection,
|
||||
],
|
||||
);
|
||||
Reference in New Issue
Block a user