P1: typed RPC bridge + FileSystemProvider + dual-panel local browsing

- shared/types + shared/rpc: full wire contract (Result envelope, no exceptions cross the bridge)
- FileSystemProvider interface, LocalProvider, SessionRegistry with built-in 'local'
- walk.ts: provider-generic recursive walk + removeRecursive
- rpc-handlers wired into BrowserWindow; 10min request timeout for slow SFTP ops
- Angular: RpcService (Electroview bridge + plain-browser guard), PanelsService with
  signals-based PanelState (sort/cursor/selection), FilePanel component with
  keyboard nav (arrows/Space/Enter/Backspace/Tab), path bar, toasts
- verified: both panels listDir home over the bridge in the running app

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Jokin
2026-07-11 13:35:02 +02:00
co-authored by Claude Fable 5
parent 8092cb0c08
commit a150c5ee2e
17 changed files with 1062 additions and 15 deletions
+34
View File
@@ -0,0 +1,34 @@
const SIZE_UNITS = ['B', 'KB', 'MB', 'GB', 'TB'];
export function formatSize(bytes: number): string {
let value = bytes;
let unit = 0;
while (value >= 1024 && unit < SIZE_UNITS.length - 1) {
value /= 1024;
unit++;
}
return `${unit === 0 ? value : value.toFixed(1)} ${SIZE_UNITS[unit]}`;
}
const DATE_FORMAT = new Intl.DateTimeFormat(undefined, {
year: '2-digit',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
});
export function formatDate(epochMs: number): string {
if (!epochMs) return '';
return DATE_FORMAT.format(new Date(epochMs));
}
/** 0o755 -> "rwxr-xr-x" */
export function formatMode(mode: number): string {
const flags = 'rwxrwxrwx';
let out = '';
for (let i = 0; i < 9; i++) {
out += mode & (0o400 >> i) ? flags[i] : '-';
}
return out;
}