Files
miniSCP/src/shared/types.ts
T
jgamboaandClaude Fable 5 e2f3737656 Redo connection manager: Stacks, More options, drag & drop, WinSCP import
Folders become Stacks (connections.json v2, no v1 migration): collapsible
stack-first list, open-stack-in-tabs (first reuses a pristine tab), drag
connections between stacks. More... reveals a per-connection Local
directory applied to the other panel when local and untouched. Import
reads a WinSCP.ini export incl. deobfuscated passwords.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-13 18:28:30 +02:00

137 lines
3.7 KiB
TypeScript

export type EntryType = "file" | "dir" | "symlink";
export interface FileEntry {
name: string;
path: string; // absolute path on its filesystem
type: EntryType;
size: number; // bytes
mtime: number; // epoch milliseconds
mode: number; // permission bits only (masked & 0o7777)
}
/** Every RPC response uses this envelope; errors never cross the bridge as exceptions. */
export type Result<T = object> = ({ ok: true } & T) | { ok: false; error: string };
export type AuthConfig =
| { kind: "password"; password: string }
| { kind: "key"; privateKeyPath: string; passphrase?: string }
| { kind: "agent" };
export interface ConnectionConfig {
host: string;
port: number;
username: string;
auth: AuthConfig;
initialPath?: string | null;
}
export interface SavedConnection extends ConnectionConfig {
id: string;
stackId: string | null;
name: string;
/** Other-panel local dir applied when that panel is local and untouched. */
localDir?: string | null;
}
/** A named group of connections that can be opened together as tabs. */
export interface Stack {
id: string;
name: string;
/** Collapsed in the connection-manager list (UI state, persisted). */
collapsed?: boolean;
}
/** A concrete host alias resolved from ~/.ssh/config (read-only). */
export interface SshConfigHost {
name: string; // the Host alias as written
hostname: string; // resolved HostName (defaults to alias)
port: number;
username: string;
identityFile?: string; // first existing IdentityFile, absolute path
unsupported?: "proxy"; // ProxyJump/ProxyCommand present — direct connect can't work
}
export interface ConnectionsFile {
version: 2;
stacks: Stack[];
connections: SavedConnection[];
}
export type AccentTone =
| "graphite"
| "blue"
| "indigo"
| "purple"
| "rose"
| "orange"
| "green"
| "teal";
export interface AppSettings {
theme: "system" | "light" | "dark";
/** Dark appearance: grey ("dark") or near-black AMOLED ("darker"). */
darkTone: "dark" | "darker";
/** Accent tone for chrome and selection tint; graphite = neutral zinc. */
accent: AccentTone;
/** File-list icons: plain neutral glyphs, or per-category glyphs and colors. */
iconColors: "plain" | "multi";
speedUnit: "MBps" | "Mbps";
/** Size of the panel interface: file list, path bar, header controls. */
textSize: "compact" | "default" | "large";
/** Run transfer jobs one at a time, or several in parallel. */
transferMode: "single" | "multi";
/** How many jobs run at once when transferMode is "multi". */
transferConcurrency: number;
/** Remove completed transfers from the list automatically. */
autoClearCompleted: boolean;
/** Edit files with the built-in editor or an external application. */
editor: "builtin" | "custom";
/** Full path to the external editor .app; empty = OS default application. */
editorApp: string;
}
export const DEFAULT_SETTINGS: AppSettings = {
theme: "system",
darkTone: "dark",
accent: "blue",
iconColors: "multi",
speedUnit: "MBps",
textSize: "default",
transferMode: "single",
transferConcurrency: 3,
autoClearCompleted: true,
editor: "builtin",
editorApp: "",
};
export function effectiveConcurrency(settings: AppSettings): number {
if (settings.transferMode === "single") return 1;
return Math.max(1, Math.min(8, Math.round(settings.transferConcurrency) || 1));
}
export type TransferState =
| "queued"
| "scanning"
| "running"
| "completed"
| "failed"
| "cancelled";
export interface TransferSnapshot {
id: string;
name: string; // display name (basename of source)
srcSessionId: string;
srcPath: string;
dstSessionId: string;
dstDir: string;
state: TransferState;
totalFiles: number;
totalBytes: number;
doneFiles: number;
doneBytes: number;
currentFile: string;
currentFileBytes: number;
currentFileTotal: number;
error?: string;
}