fix(electrobun): native folder picker dialog replaces inline PathBrowser

- Uses Electrobun's Utils.openFileDialog (canChooseDirectory: true)
- files.pickDirectory + files.homeDir RPC handlers
- ProjectWizard: 📂 button opens native OS dialog
- Removed broken inline PathBrowser (process.env.HOME not in WebView)
This commit is contained in:
Hibryda 2026-03-22 11:38:19 +01:00
parent 45bca3b96f
commit bfc63bb595
3 changed files with 44 additions and 7 deletions

View file

@ -6,7 +6,7 @@
*/
import fs from "fs";
import { BrowserWindow, BrowserView, Updater } from "electrobun/bun";
import { BrowserWindow, BrowserView, Updater, Utils } from "electrobun/bun";
import { PtyClient } from "./pty-client.ts";
import { settingsDb } from "./settings-db.ts";
import { sessionDb } from "./session-db.ts";
@ -128,6 +128,24 @@ const rpc = BrowserView.defineRPC<PtyRPCSchema>({
// Git
...gitHandlers,
// Native folder picker dialog
"files.pickDirectory": async ({ startingFolder }) => {
try {
const paths = await Utils.openFileDialog({
startingFolder: startingFolder || "~/",
canChooseFiles: false,
canChooseDirectory: true,
allowsMultipleSelection: false,
});
return { path: paths?.[0] ?? null };
} catch { return { path: null }; }
},
// Home directory
"files.homeDir": async () => {
return { path: process.env.HOME || "/home" };
},
// Project templates (hardcoded list)
"project.templates": async () => ({
templates: [

View file

@ -210,10 +210,22 @@
function handleBrowserSelect(path: string) {
localPath = path;
showBrowser = false;
validatePath(path);
}
async function handleNativeBrowse() {
try {
const result = await appRpc.request['files.pickDirectory']({ startingFolder: localPath || '~/' });
if (result?.path) {
localPath = result.path;
validatePath(result.path);
}
} catch {
// Fallback: native dialog not available, user types path manually
console.warn('[wizard] Native folder picker not available');
}
}
// Validation indicator
function validationIcon(state: typeof pathValid): string {
switch (state) {
@ -280,16 +292,13 @@
placeholder={t('wizard.step1.pathPlaceholder' as any)}
bind:value={localPath}
oninput={() => validatePath(localPath)} />
<button class="wz-browse-btn" onclick={() => showBrowser = !showBrowser}
aria-label={t('wizard.step1.browse' as any)}>🔍</button>
<button class="wz-browse-btn" onclick={handleNativeBrowse}
aria-label={t('wizard.step1.browse' as any)}>📂</button>
{#if pathValid !== 'idle'}
<span class="wz-validation" style:color={validationColor(pathValid)}>
{validationIcon(pathValid)}
</span>
{/if}
{#if showBrowser}
<PathBrowser onSelect={handleBrowserSelect} onClose={() => showBrowser = false} />
{/if}
</div>
{#if pathValid === 'valid' && isGitRepo}
<span class="wz-badge git-badge">{t('wizard.step1.gitDetected' as any)} ({gitBranch})</span>

View file

@ -146,6 +146,16 @@ export type PtyRPCRequests = {
error?: string;
};
};
/** Native folder picker dialog */
"files.pickDirectory": {
params: { startingFolder?: string };
response: { path: string | null };
};
/** Get home directory path */
"files.homeDir": {
params: {};
response: { path: string };
};
/** Write text content to a file (atomic temp+rename). */
"files.write": {
params: { path: string; content: string };