v1.1: fix transfer freeze, session tabs, per-panel toolbars, status bar
Freeze root cause: TransfersService consumed transferUpdate through an effect that both read and wrote the jobMap signal — the first progress message spun the effect into an infinite re-run loop, pegging the webview thread while the copy completed fine bun-side. Push messages now flow through plain callback registries on RpcService (also stops signal coalescing from dropping progress snapshots). Verified live: a 60MB boot-time self-test copy streamed progress into the running UI and the post-completion panel refreshes arrived. - Tabs: workspaces (left+right PanelState pair each) in PanelsService; tab bar replaces the header; sessions persist in background tabs; Cmd+T/Cmd+W/Ctrl+Tab; closing a tab disconnects its sessions; last tab can't close - Per-panel toolbar (top, icon-only): direction-explicit copy (-> / <-), rename, new folder/file, chmod, delete; panel footers removed - VSCode-style status bar: transfer summary (spinner/percent/queued/failures, click to expand the job list) + active panel info; function bar removed - transfer details list is collapsible, auto-expands on failure Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+22
-5
@@ -6,18 +6,21 @@ import { ChmodDialog } from './dialogs/chmod-dialog';
|
||||
import { ConfirmDialog } from './dialogs/confirm-dialog';
|
||||
import { PromptDialog } from './dialogs/prompt-dialog';
|
||||
import { DialogsService } from './dialogs.service';
|
||||
import { FileActionsService } from './file-actions.service';
|
||||
import { FilePanel } from './file-panel/file-panel';
|
||||
import { PanelsService } from './panels.service';
|
||||
import { RpcService } from './rpc.service';
|
||||
import { StatusBar } from './status-bar/status-bar';
|
||||
import { TabBar } from './tab-bar/tab-bar';
|
||||
import { ToastService } from './toast.service';
|
||||
import { TransferBar } from './transfer-bar/transfer-bar';
|
||||
import { TransfersService } from './transfers.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
imports: [
|
||||
NgIcon,
|
||||
FilePanel,
|
||||
TabBar,
|
||||
StatusBar,
|
||||
PromptDialog,
|
||||
ConfirmDialog,
|
||||
ChmodDialog,
|
||||
@@ -25,19 +28,33 @@ import { TransfersService } from './transfers.service';
|
||||
ConnectionManager,
|
||||
],
|
||||
templateUrl: './app.html',
|
||||
host: { '(window:keydown)': 'onWindowKeydown($event)' },
|
||||
})
|
||||
export class App {
|
||||
readonly appName = BRANDING.appName;
|
||||
readonly rpc = inject(RpcService);
|
||||
readonly toast = inject(ToastService);
|
||||
readonly dialogs = inject(DialogsService);
|
||||
readonly actions = inject(FileActionsService);
|
||||
readonly transfers = inject(TransfersService);
|
||||
readonly panels = inject(PanelsService);
|
||||
|
||||
constructor() {
|
||||
document.title = BRANDING.appName;
|
||||
}
|
||||
|
||||
/** Tab (workspace) shortcuts — panel-level keys live on the panels themselves. */
|
||||
onWindowKeydown(event: KeyboardEvent): void {
|
||||
const mod = event.metaKey || event.ctrlKey;
|
||||
if (mod && event.key.toLowerCase() === 't') {
|
||||
event.preventDefault();
|
||||
this.panels.newWorkspace();
|
||||
} else if (mod && event.key.toLowerCase() === 'w') {
|
||||
event.preventDefault();
|
||||
this.panels.closeWorkspace(this.panels.activeWorkspaceId());
|
||||
} else if (event.ctrlKey && event.key === 'Tab') {
|
||||
event.preventDefault();
|
||||
this.panels.cycleWorkspace(event.shiftKey ? -1 : 1);
|
||||
}
|
||||
}
|
||||
|
||||
toastIcon(kind: 'error' | 'info' | 'success'): string {
|
||||
if (kind === 'error') return 'mynaXCircle';
|
||||
if (kind === 'success') return 'mynaCheckCircle';
|
||||
|
||||
Reference in New Issue
Block a user