Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: browser settings in the settings page #440

Merged
merged 3 commits into from
Sep 6, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions actions/browser.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
'use server';

import fs from 'fs';
import os from 'os';
import path from 'path';

export type BrowserSettings = {
headless: boolean;
useDefaultSession: boolean;
};

const defaultSettings: BrowserSettings = {
headless: false,
useDefaultSession: false,
};

export async function getBrowserSettings(): Promise<BrowserSettings> {
const location = await browserSettingsLocation();
if (fs.existsSync(location)) {
const settings = fs.readFileSync(location, 'utf-8');
return JSON.parse(settings) as BrowserSettings;
}

return defaultSettings;
}

export async function setBrowserSettings(settings: BrowserSettings) {
const location = await browserSettingsLocation();
fs.writeFileSync(location, JSON.stringify(settings, null, 2));
tylerslaton marked this conversation as resolved.
Show resolved Hide resolved
}

export async function browserSettingsLocation(): Promise<string> {
const homeDir = os.homedir();
let configDir;
if (os.platform() === 'darwin') {
configDir =
process.env.XDG_CONFIG_HOME ||
path.join(homeDir, 'Library', 'Application Support');
} else if (os.platform() === 'win32') {
configDir = path.join(homeDir, 'AppData', 'Local');
} else if (os.platform() === 'linux') {
configDir = process.env.XDG_CONFIG_HOME || path.join(homeDir, '.config');
} else {
throw new Error('Unsupported platform');
}

return path.join(configDir, 'acorn', 'browsersettings.json');
}
90 changes: 89 additions & 1 deletion app/settings/page.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,34 @@
'use client';

import { Button, Divider } from '@nextui-org/react';
import { Button, Chip, Divider, Switch, Tooltip } from '@nextui-org/react';
import { GoDownload } from 'react-icons/go';
import { useEffect, useState } from 'react';
import {
BrowserSettings,
getBrowserSettings,
setBrowserSettings,
} from '@/actions/browser';
import { IoIosInformationCircleOutline } from 'react-icons/io';

export default function Settings() {
const [settings, setSettings] = useState({
headless: false,
useDefaultSession: false,
} as BrowserSettings);
const [loading, setLoading] = useState(true);
const [saveButtonText, setSaveButtonText] = useState('Save Settings');

useEffect(() => {
getBrowserSettings().then((settings) => {
setSettings(settings);
setLoading(false);
});
}, []);

async function saveSettings() {
await setBrowserSettings(settings);
}

return (
<div className="container mx-auto max-w-6xl py-10 px-6">
<h1 className="text-3xl font-bold mb-8">Settings</h1>
Expand All @@ -22,6 +47,69 @@ export default function Settings() {
Export Acorn Logs
</Button>
</section>
<section>
<h2 className="text-2xl font-semibold mb-4">Browser Tool</h2>
{loading ? (
<p>Loading...</p>
) : (
<>
<div className="mt-2 mb-2 flex items-center">
<Switch
isSelected={settings.headless}
onValueChange={(isSelected) => {
setSettings((prevState) => ({
...prevState,
headless: isSelected,
}));
}}
>
Headless Mode
</Switch>
<Tooltip
content="Headless Mode runs the browser without a graphical interface."
placement="right"
>
<Chip className="ml-2 font-mono cursor-default">i</Chip>
</Tooltip>
</div>
<div className="mt-2 mb-2 flex items-center">
<Switch
isSelected={settings.useDefaultSession}
onValueChange={(isSelected) => {
setSettings((prevState) => ({
...prevState,
useDefaultSession: isSelected,
}));
}}
>
Use Default Session
</Switch>
<Tooltip
content="Use Default Session will use your existing default Google Chrome session. When this setting is enabled, Chrome must be closed before running the browser tool."
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit:

Right now this goes all the way to the edge of my app and its a little hard to read. Screenshot 2024-09-06 at 9 38 07 AM
Suggested change
<Tooltip
content="Use Default Session will use your existing default Google Chrome session. When this setting is enabled, Chrome must be closed before running the browser tool."
<Tooltip
classNames={{base: "w-1/2"}}
content="Use Default Session will use your existing default Google Chrome session. When this setting is enabled, Chrome must be closed before running the browser tool."
Could we add that max width so it looks more like this? Screenshot 2024-09-06 at 9 43 40 AM

placement="right"
>
<Chip className="ml-2 font-mono cursor-default">i</Chip>
</Tooltip>
</div>
</>
)}
</section>
<Button
className="w-full md:w-auto"
onClick={() => {
setSaveButtonText('Saving...');
saveSettings().then(() => {
setSaveButtonText('Saved!');
setTimeout(() => {
setSaveButtonText('Save Settings');
}, 1000);
});
}}
color="primary"
variant="flat"
>
{saveButtonText}
</Button>
</div>
</div>
);
Expand Down
21 changes: 21 additions & 0 deletions electron/config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,25 @@ import { join, dirname, parse } from 'path';
import log from 'electron-log/main.js';
import util from 'util';
import { renameSync } from 'fs';
import os from 'os';

function browserSettingsLocation() {
const homeDir = os.homedir();
let configDir;
if (os.platform() === 'darwin') {
configDir =
process.env.XDG_CONFIG_HOME ||
join(homeDir, 'Library', 'Application Support');
} else if (os.platform() === 'win32') {
configDir = join(homeDir, 'AppData', 'Local');
} else if (os.platform() === 'linux') {
configDir = process.env.XDG_CONFIG_HOME || join(homeDir, '.config');
} else {
throw new Error('Unsupported platform');
}

return join(configDir, 'acorn', 'browsersettings.json');
}
Comment on lines +9 to +25
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I hate how this function is duplicated from actions/browser.tsx. But I'm not sure if there is a way for me to define it in one place and have it be callable from both places. Please let me know if there is a way to do that.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That I personally know of, no. I've had a lot of similar headaches. Ideally we'd make a global lib package that both the Next app and electron could import. To do that right though I think we'd need the socket server and config code to be in typescript so it isn't super simple in just this PR.


// App config
const dev = !app.isPackaged;
Expand All @@ -14,6 +33,7 @@ const resourcesDir = dirname(appDir);
const dataDir = join(app.getPath('userData'), appName);
const threadsDir = process.env.THREADS_DIR || join(dataDir, 'threads');
const workspaceDir = process.env.WORKSPACE_DIR || join(dataDir, 'workspace');
const browserSettingsFile = browserSettingsLocation();
const port =
process.env.PORT ||
(!dev ? await getPort({ portRange: [30000, 40000] }) : 3000);
Expand Down Expand Up @@ -92,4 +112,5 @@ export const config = {
gptscriptBin,
gatewayUrl,
knowledgeBin,
browserSettingsFile,
};
1 change: 1 addition & 0 deletions electron/main.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ async function startServer() {
process.env.WORKSPACE_DIR = config.workspaceDir;
process.env.GPTSCRIPT_GATEWAY_URL = config.gatewayUrl;
process.env.GPTSCRIPT_OPENAPI_REVAMP = 'true';
process.env.GPTSCRIPT_BROWSER_SETTINGS_FILE = config.browserSettingsFile;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This environment variable is read by the browser tool itself so that it knows where to look for its settings.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this mean that for various tools that have settings that they will all have their own settings files?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose so, but right now the browser tool is the only tool that reads any kind of settings file for itself.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense. No need to prematurely optimize yet, just wanted to understand for the future.


console.log(`GPTSCRIPT_BIN=${config.gptscriptBin}`);

Expand Down
Loading