Windows compatibility pass (beta target)
External editor via cmd/start + exe picker; Permissions hidden for Windows-local (chmod only flips read-only there); Explorer/Recycle Bin wording; Ctrl vs Cmd shortcut labels; separator-aware path joins + drive-root detection; drives list in the panel source picker; icon.ico + colored tray icon; icacls ACL on connections.json; README Windows (beta) section with upstream known issues and a smoke-test checklist. Runtime paths pending first boot on a real Windows machine. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -63,13 +63,15 @@
|
||||
>
|
||||
<ng-icon name="mynaFilePlus" size="var(--action-icon)" />
|
||||
</button>
|
||||
<button
|
||||
(click)="run('chmod')"
|
||||
title="Permissions"
|
||||
class="grid size-(--action-h) shrink-0 place-items-center rounded-md text-muted-foreground hover:bg-accent hover:text-foreground"
|
||||
>
|
||||
<ng-icon name="mynaLock" size="var(--action-icon)" />
|
||||
</button>
|
||||
@if (chmodAvailable()) {
|
||||
<button
|
||||
(click)="run('chmod')"
|
||||
title="Permissions"
|
||||
class="grid size-(--action-h) shrink-0 place-items-center rounded-md text-muted-foreground hover:bg-accent hover:text-foreground"
|
||||
>
|
||||
<ng-icon name="mynaLock" size="var(--action-icon)" />
|
||||
</button>
|
||||
}
|
||||
<button
|
||||
(click)="run('delete')"
|
||||
title="Delete (F8 / Del)"
|
||||
@@ -95,6 +97,17 @@
|
||||
}
|
||||
</button>
|
||||
|
||||
<!-- Windows drive roots (empty list elsewhere) -->
|
||||
@for (drive of drives(); track drive) {
|
||||
<button
|
||||
(click)="pickDrive(drive)"
|
||||
class="flex w-full items-center gap-2 py-1.5 pr-3 pl-6 text-left text-(length:--path-font) hover:bg-accent"
|
||||
>
|
||||
<ng-icon name="mynaHardDrive" size="var(--action-icon)" class="shrink-0 text-muted-foreground" />
|
||||
<span class="flex-1 font-mono">{{ drive }}</span>
|
||||
</button>
|
||||
}
|
||||
|
||||
@if (connections.grouped().loose.length || connections.grouped().stacks.length) {
|
||||
<div class="my-1 border-t border-border"></div>
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import { FileActionsService } from '../file-actions.service';
|
||||
import { fileGlyph, fileIconClass, fileKind } from '../file-icons';
|
||||
import { formatDate, formatMode, formatSize } from '../format';
|
||||
import { PanelsService, type Side, type SortKey } from '../panels.service';
|
||||
import { IS_WINDOWS } from '../platform';
|
||||
import { RpcService } from '../rpc.service';
|
||||
import { SettingsService } from '../settings.service';
|
||||
import { TransfersService } from '../transfers.service';
|
||||
@@ -56,6 +57,10 @@ export class FilePanel {
|
||||
|
||||
readonly pathDraft = signal('');
|
||||
readonly menuOpen = signal(false);
|
||||
/** Windows drive roots for the source picker; always empty elsewhere. */
|
||||
readonly drives = signal<string[]>([]);
|
||||
/** chmod on Windows local files only flips the read-only bit — hide it. */
|
||||
readonly chmodAvailable = computed(() => !(IS_WINDOWS && !this.isRemote()));
|
||||
|
||||
private readonly listEl = viewChild.required<ElementRef<HTMLDivElement>>('list');
|
||||
private lastClickedIndex = 0;
|
||||
@@ -79,7 +84,18 @@ export class FilePanel {
|
||||
void this.rpc.request.showColumnsMenu({ visible: this.settings.columns() });
|
||||
}
|
||||
|
||||
pickDrive(drive: string): void {
|
||||
this.menuOpen.set(false);
|
||||
this.activate();
|
||||
void this.panel().load(drive);
|
||||
}
|
||||
|
||||
constructor() {
|
||||
if (IS_WINDOWS && this.rpc.available) {
|
||||
void this.rpc.request.listDrives({}).then((res) => {
|
||||
if (res.ok) this.drives.set(res.drives);
|
||||
});
|
||||
}
|
||||
// keep the editable path bar in sync with the actual cwd
|
||||
effect(() => this.pathDraft.set(this.panel().cwd()));
|
||||
// focus follows the active side (Tab switches panels, dialogs refocus on close)
|
||||
|
||||
Reference in New Issue
Block a user