The win7 skin is dropped. Everything else the branch built stays: Linux support and the HTML context menus, the workspace-tab menu, the continuous interface scale (rem everywhere, stepper, Ctrl/Cmd +/-/0) and the core/ service layer. The modern tree already carried all of them, and nothing outside skins/7like/ imported the win7 tree except main.ts and styles.css. Removed: the skins/7like/ tree (5.1k lines, fonts), the 7.css dependency, the skin setting and its options row + strings in all 7 locales, the frameless-window plumbing (window-control RPCs, windowState push, trackMaximizeState, the synthesized resize grip and its postinstall watchdog), the session-skin pinning in buildPreload/chromeOptions, the skin/skinfix cascade layers, and the win7-only probes and screenshot harness (the harness cannot render the modern tree: plain Firefox has no RPC bridge). chromeOptions() stays as the one shared frame decision. Fixed on the way out: - index.html's per-theme pre-paint background is restored. The branch had replaced it with a win7-only transparent rule, so modern dark windows had silently lost one of the three flash guards. - editor-windows.ts wrote its window-key separator as a literal NUL byte, which made git and grep treat the file as binary; it is `\0` now (same string at runtime). No settings migration: a stale "skin" key is carried harmlessly by the store's spread-merge and dropped on the next save. UI bundle: 616.7 kB -> 405.4 kB, back under the 500 kB budget. Docs: architecture, gotchas and platform-notes lose the win7 material but keep what stays true (construction-time preloads/frames, drag regions ignoring preventDefault, electrobun's missing resize/maximize primitives); flash-prevention, dev-URL and Bun-panic notes move back under Electrobun; stale context-menu/tab-bar links fixed; README documents the scale keys. Co-Authored-By: Claude <noreply@anthropic.com>
202 lines
7.5 KiB
TypeScript
202 lines
7.5 KiB
TypeScript
import type {
|
|
AppSettings,
|
|
ConnectionConfig,
|
|
ConnectionsFile,
|
|
EntryType,
|
|
FileEntry,
|
|
Result,
|
|
SavedConnection,
|
|
SshConfigHost,
|
|
Stack,
|
|
TransferSnapshot,
|
|
} from "./types";
|
|
|
|
/** Everything an editor window needs to know about the file it hosts. */
|
|
export interface EditorOpenContext {
|
|
sessionId: string;
|
|
path: string;
|
|
name: string;
|
|
sessionTitle: string;
|
|
}
|
|
|
|
// Structurally equivalent to electrobun's ElectrobunRPCSchema, written in
|
|
// resolved form so this file stays importable from the Angular bundle without
|
|
// pulling in bun-only type modules.
|
|
//
|
|
// bun.requests = calls the webview makes, handled in src/bun/rpc-handlers.ts
|
|
// webview.messages = push events from bun, handled in ui rpc.service.ts
|
|
//
|
|
// ONE schema serves both window kinds (main + editor): electrobun allows
|
|
// partial handler sets, and messages nobody listens to are silently dropped,
|
|
// so each side only implements/hears what applies to it.
|
|
export type AppRPC = {
|
|
bun: {
|
|
requests: {
|
|
// sessions
|
|
connect: {
|
|
params: { config: ConnectionConfig };
|
|
response: Result<{ sessionId: string; homeDir: string; fsKey: string }>;
|
|
};
|
|
disconnect: { params: { sessionId: string }; response: Result };
|
|
// filesystem (uniform across "local" and sftp sessions)
|
|
listDir: {
|
|
params: { sessionId: string; path: string | null }; // null -> home dir
|
|
response: Result<{ path: string; entries: FileEntry[] }>;
|
|
};
|
|
// Local dirs to fs.watch for auto-refresh (the active tab's local panels);
|
|
// a change pushes pathRefresh. Remote panels are polled UI-side instead.
|
|
setWatchedDirs: { params: { dirs: string[] }; response: Result };
|
|
mkdir: { params: { sessionId: string; path: string }; response: Result };
|
|
createFile: { params: { sessionId: string; path: string }; response: Result };
|
|
rename: {
|
|
params: { sessionId: string; oldPath: string; newPath: string };
|
|
response: Result;
|
|
};
|
|
deleteEntries: {
|
|
params: { sessionId: string; entries: { path: string; type: EntryType }[] };
|
|
response: Result;
|
|
};
|
|
chmod: {
|
|
params: { sessionId: string; paths: string[]; mode: number };
|
|
response: Result;
|
|
};
|
|
// transfers
|
|
enqueueTransfers: {
|
|
params: {
|
|
srcSessionId: string;
|
|
items: { path: string; type: EntryType }[];
|
|
dstSessionId: string;
|
|
dstDir: string;
|
|
};
|
|
response: Result<{ jobIds: string[] }>;
|
|
};
|
|
cancelTransfer: { params: { jobId: string }; response: Result };
|
|
dismissTransfer: { params: { jobId: string }; response: Result };
|
|
// connection store
|
|
getConnections: {
|
|
params: Record<string, never>;
|
|
response: Result<{ store: ConnectionsFile }>;
|
|
};
|
|
upsertConnection: {
|
|
params: { connection: SavedConnection };
|
|
response: Result<{ id: string }>;
|
|
};
|
|
deleteConnection: { params: { id: string }; response: Result };
|
|
upsertStack: { params: { stack: Stack }; response: Result<{ id: string }> };
|
|
deleteStack: { params: { id: string }; response: Result };
|
|
/** Native file picker + parse of a WinSCP.ini export into the store. */
|
|
importWinScp: {
|
|
params: Record<string, never>;
|
|
response: Result<{ connections: number; stacks: number; skipped: number }>;
|
|
};
|
|
getSshConfigHosts: {
|
|
params: Record<string, never>;
|
|
response: Result<{ hosts: SshConfigHost[] }>;
|
|
};
|
|
// settings
|
|
getSettings: {
|
|
params: Record<string, never>;
|
|
response: Result<{ settings: AppSettings }>;
|
|
};
|
|
saveSettings: { params: { settings: AppSettings }; response: Result };
|
|
// file editing
|
|
readFile: {
|
|
params: { sessionId: string; path: string };
|
|
response: Result<{ content: string }>;
|
|
};
|
|
writeFile: {
|
|
params: { sessionId: string; path: string; content: string };
|
|
response: Result;
|
|
};
|
|
editExternal: {
|
|
params: { sessionId: string; path: string };
|
|
response: Result<{ watching: boolean }>;
|
|
};
|
|
pickEditorApp: {
|
|
params: Record<string, never>;
|
|
response: Result<{ path: string | null }>;
|
|
};
|
|
pickKeyFile: {
|
|
params: Record<string, never>;
|
|
response: Result<{ path: string | null }>;
|
|
};
|
|
getEditLeftovers: {
|
|
params: Record<string, never>;
|
|
response: Result<{ names: string[] }>;
|
|
};
|
|
clearEditLeftovers: { params: Record<string, never>; response: Result };
|
|
// local shell integration
|
|
/**
|
|
* Shell actions the context menu triggers on a LOCAL path. The menu
|
|
* itself is HTML (ui/src/app/core/context-menu.service.ts) — electrobun's native
|
|
* context menu is a no-op on Linux — but these three still need the
|
|
* bun side's Utils.
|
|
*/
|
|
shellItemAction: {
|
|
params: { action: "reveal" | "open" | "copyPath"; path: string };
|
|
response: Result;
|
|
};
|
|
moveToTrash: { params: { path: string }; response: Result };
|
|
/** Native About box (name, Build n, commit, engine versions). */
|
|
showAbout: { params: Record<string, never>; response: Result };
|
|
/** Windows drive roots for the local panel ("C:\", …); empty elsewhere. */
|
|
listDrives: { params: Record<string, never>; response: Result<{ drives: string[] }> };
|
|
// editor windows
|
|
/** Main window only: open (or focus) a native editor window. */
|
|
openEditor: { params: EditorOpenContext; response: Result };
|
|
/** Editor windows only — handled by that window's own rpc closure. */
|
|
editorSave: { params: { content: string }; response: Result };
|
|
editorClose: { params: Record<string, never>; response: Result };
|
|
// connection-manager window
|
|
/** Main window: open (or focus) the single connection-manager window. */
|
|
openConnectionManager: { params: Record<string, never>; response: Result };
|
|
/** Manager window only: connect/open-stack run in the MAIN window. */
|
|
managerConnect: { params: { id: string }; response: Result };
|
|
managerOpenStack: { params: { id: string }; response: Result };
|
|
managerClose: { params: Record<string, never>; response: Result };
|
|
// auto-updater (electrobun Updater)
|
|
/** Main window: re-run the update check on demand (menu item). */
|
|
checkForUpdate: {
|
|
params: Record<string, never>;
|
|
response: Result<{ updateAvailable: boolean; version: string }>;
|
|
};
|
|
/** Download the pending update (patch-chain, else full). Progress arrives via updateStatus. */
|
|
downloadUpdate: { params: Record<string, never>; response: Result };
|
|
/** Swap in the downloaded update and relaunch — quits the app, so may not resolve. */
|
|
applyUpdate: { params: Record<string, never>; response: Result };
|
|
};
|
|
messages: {
|
|
/** Editor → bun draft mirror; safety net for the non-cancellable native close. */
|
|
editorState: { dirty: boolean; content: string };
|
|
};
|
|
};
|
|
webview: {
|
|
requests: Record<never, never>;
|
|
messages: {
|
|
transferUpdate: TransferSnapshot;
|
|
sessionClosed: { sessionId: string; reason: string };
|
|
menuAction: { action: string };
|
|
/** bun → editor windows when the main window saves settings. */
|
|
settingsChanged: { settings: AppSettings };
|
|
/** bun → main after an editor save, so matching panels refresh. */
|
|
pathRefresh: { sessionId: string; dir: string };
|
|
/** bun → one editor: run the in-window close flow (dirty prompt). */
|
|
editorCloseRequest: Record<string, never>;
|
|
/** bun → main: the modal connection manager opened/closed. */
|
|
managerState: { open: boolean };
|
|
/** bun → main: the manager window changed the connection store. */
|
|
connectionsChanged: Record<string, never>;
|
|
/**
|
|
* bun → main: auto-updater lifecycle, drives the tab-bar update pill.
|
|
* "ready" is not a phase — the UI derives it from downloadUpdate resolving ok.
|
|
*/
|
|
updateStatus: {
|
|
phase: "available" | "downloading" | "error";
|
|
version?: string;
|
|
progress?: number;
|
|
error?: string;
|
|
};
|
|
};
|
|
};
|
|
};
|