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:
@@ -0,0 +1,63 @@
|
||||
import { Component, inject } from '@angular/core';
|
||||
import { NgIcon } from '@ng-icons/core';
|
||||
import { PanelsService } from '../panels.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-tab-bar',
|
||||
imports: [NgIcon],
|
||||
template: `
|
||||
<div class="flex items-center gap-0.5 border-b border-border px-1.5 pt-1">
|
||||
@for (ws of panels.workspaces(); track ws.id) {
|
||||
<div
|
||||
class="group relative flex max-w-52 items-center rounded-t-md"
|
||||
[class.bg-accent]="ws.id === panels.activeWorkspaceId()"
|
||||
>
|
||||
<button
|
||||
(click)="panels.setActiveWorkspace(ws.id)"
|
||||
class="flex min-w-0 items-center gap-1.5 py-1.5 pr-1 pl-2.5 text-xs"
|
||||
[class.text-foreground]="ws.id === panels.activeWorkspaceId()"
|
||||
[class.text-muted-foreground]="ws.id !== panels.activeWorkspaceId()"
|
||||
[title]="panels.workspaceName(ws)"
|
||||
>
|
||||
<ng-icon
|
||||
[name]="panels.workspaceIsRemote(ws) ? 'mynaServers' : 'mynaHardDrive'"
|
||||
size="0.85rem"
|
||||
class="shrink-0"
|
||||
[class.text-primary]="panels.workspaceIsRemote(ws)"
|
||||
/>
|
||||
<span class="truncate">{{ panels.workspaceName(ws) }}</span>
|
||||
</button>
|
||||
@if (panels.workspaces().length > 1) {
|
||||
<button
|
||||
(click)="close($event, ws.id)"
|
||||
title="Close tab (⌘W)"
|
||||
class="mr-1 grid size-4 shrink-0 place-items-center rounded text-muted-foreground opacity-0 group-hover:opacity-100 hover:bg-border hover:text-foreground"
|
||||
>
|
||||
<ng-icon name="mynaX" size="0.7rem" />
|
||||
</button>
|
||||
} @else {
|
||||
<span class="mr-1 size-4 shrink-0"></span>
|
||||
}
|
||||
@if (ws.id === panels.activeWorkspaceId()) {
|
||||
<div class="absolute inset-x-0 -bottom-px h-0.5 rounded-full bg-primary"></div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
<button
|
||||
(click)="panels.newWorkspace()"
|
||||
title="New tab (⌘T)"
|
||||
class="ml-0.5 grid size-6 place-items-center rounded-md text-muted-foreground hover:bg-accent hover:text-foreground"
|
||||
>
|
||||
<ng-icon name="mynaPlus" size="0.9rem" />
|
||||
</button>
|
||||
</div>
|
||||
`,
|
||||
})
|
||||
export class TabBar {
|
||||
readonly panels = inject(PanelsService);
|
||||
|
||||
close(event: MouseEvent, id: number): void {
|
||||
event.stopPropagation();
|
||||
this.panels.closeWorkspace(id);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user