Edit file: built-in editor + external editor with watch & auto-upload
- Built-in editor (default): large modal with monospace textarea, Cmd+S save, dirty guard; reads/writes through the provider streams so it works on local and remote files identically (2MB cap with a friendly error) - External editor: remote files download to appDataDir/edits/<id>, open via macOS `open -a`, the temp DIR is watched (survives atomic rename-saves) and every save enqueues a normal upload job (progress/errors in the transfer list); watchers + temp dirs are cleaned when the session disconnects - Editor setting: Built-in | Custom with a NATIVE app picker (electrobun openFileDialog, /Applications, .app filter) and reset-to-default - Leftover temp files from a crash prompt for cleanup at boot - F4, toolbar button (mynaFileText), and File > Edit File (Cmd+E) menu entry - README: feature notes + Portability notes (open/start/xdg-open seam documented in code and README per user request) Verified headless against the box: sftp read/write roundtrip incl. UTF-8, size cap, watch->save->auto-upload->remote-updated, session cleanup, orphan listing and clearing. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -5,6 +5,7 @@ import { ConnectionManager } from './connection-manager/connection-manager';
|
||||
import { ConnectionsService } from './connections.service';
|
||||
import { ChmodDialog } from './dialogs/chmod-dialog';
|
||||
import { ConfirmDialog } from './dialogs/confirm-dialog';
|
||||
import { EditorDialog } from './dialogs/editor-dialog';
|
||||
import { OverwriteDialog } from './dialogs/overwrite-dialog';
|
||||
import { PromptDialog } from './dialogs/prompt-dialog';
|
||||
import { DialogsService } from './dialogs.service';
|
||||
@@ -28,6 +29,7 @@ import { TransferBar } from './transfer-bar/transfer-bar';
|
||||
ConfirmDialog,
|
||||
ChmodDialog,
|
||||
OverwriteDialog,
|
||||
EditorDialog,
|
||||
TransferBar,
|
||||
ConnectionManager,
|
||||
],
|
||||
@@ -46,9 +48,25 @@ export class App {
|
||||
document.title = BRANDING.appName;
|
||||
if (this.rpc.available) {
|
||||
this.rpc.onMenuAction((action) => this.handleMenuAction(action));
|
||||
void this.promptForEditLeftovers();
|
||||
}
|
||||
}
|
||||
|
||||
/** Temp files from external edits in a previous run (crash / quit mid-edit). */
|
||||
private async promptForEditLeftovers(): Promise<void> {
|
||||
const res = await this.rpc.request.getEditLeftovers({});
|
||||
if (!res.ok || !res.names.length) return;
|
||||
const shown = res.names.slice(0, 5).join(', ');
|
||||
const more = res.names.length > 5 ? `, +${res.names.length - 5} more` : '';
|
||||
this.dialogs.confirm.set({
|
||||
title: 'Leftover edited files',
|
||||
body: `A previous session left ${res.names.length} temporary edited file(s) behind (${shown}${more}). Clear them?`,
|
||||
confirmLabel: 'Clear',
|
||||
destructive: true,
|
||||
onConfirm: () => void this.rpc.request.clearEditLeftovers({}),
|
||||
});
|
||||
}
|
||||
|
||||
/** Native application-menu actions forwarded from the bun process. */
|
||||
private handleMenuAction(action: string): void {
|
||||
if (action.startsWith('connect:')) {
|
||||
@@ -72,6 +90,9 @@ export class App {
|
||||
case 'new-file':
|
||||
this.actions.createFile(this.panels.active());
|
||||
break;
|
||||
case 'edit-file':
|
||||
void this.actions.edit(this.panels.active());
|
||||
break;
|
||||
case 'refresh-active':
|
||||
void this.panels.active().refresh();
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user