Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
23 changes: 2 additions & 21 deletions ui/desktop/src/components/settings/app/AppSettingsSection.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useState, useEffect, useRef } from 'react';
import { Switch } from '../../ui/switch';
import UpdateSection from './UpdateSection';
import { UPDATES_ENABLED } from '../../../updates';

interface AppSettingsSectionProps {
scrollToSection?: string;
Expand All @@ -11,33 +12,13 @@ export default function AppSettingsSection({ scrollToSection }: AppSettingsSecti
const [dockIconEnabled, setDockIconEnabled] = useState(true);
const [isMacOS, setIsMacOS] = useState(false);
const [isDockSwitchDisabled, setIsDockSwitchDisabled] = useState(false);
const [updatesEnabled, setUpdatesEnabled] = useState(false);
const updateSectionRef = useRef<HTMLDivElement>(null);

// Check if running on macOS
useEffect(() => {
setIsMacOS(window.electron.platform === 'darwin');
}, []);

// Load updater state
useEffect(() => {
window.electron.getUpdaterEnabled().then((enabled) => {
setUpdatesEnabled(enabled);
});

// Listen for updater state changes
const handleUpdaterStateChange = (enabled: boolean) => {
setUpdatesEnabled(enabled);
};

window.electron.onUpdaterStateChanged(handleUpdaterStateChange);

// Cleanup listener on unmount
return () => {
window.electron.removeUpdaterStateListener(handleUpdaterStateChange);
};
}, []);

// Handle scrolling to update section
useEffect(() => {
if (scrollToSection === 'update' && updateSectionRef.current) {
Expand Down Expand Up @@ -144,7 +125,7 @@ export default function AppSettingsSection({ scrollToSection }: AppSettingsSecti
</div>

{/* Update Section */}
{updatesEnabled && (
{UPDATES_ENABLED && (
<div ref={updateSectionRef} className="mt-8 pt-8 border-t border-gray-200">
<UpdateSection />
</div>
Expand Down
10 changes: 3 additions & 7 deletions ui/desktop/src/components/settings/app/UpdateSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,6 @@ export default function UpdateSection() {
};

const installUpdate = () => {
setUpdateStatus('installing');
// This will quit the app and install the update
window.electron.installUpdate();
};

Expand All @@ -158,8 +156,6 @@ export default function UpdateSection() {
return 'Checking for updates...';
case 'downloading':
return `Downloading update... ${Math.round(progress)}%`;
case 'installing':
return 'Installing update...';
case 'ready':
return 'Update downloaded and ready to install!';
case 'success':
Expand All @@ -180,7 +176,6 @@ export default function UpdateSection() {
switch (updateStatus) {
case 'checking':
case 'downloading':
case 'installing':
return <Loader2 className="w-4 h-4 animate-spin" />;
case 'success':
return <CheckCircle className="w-4 h-4 text-green-500" />;
Expand Down Expand Up @@ -257,9 +252,10 @@ export default function UpdateSection() {
{/* Update information */}
{updateInfo.isUpdateAvailable && (
<div className="text-xs text-textSubtle mt-4 space-y-1">
<p>Update will be downloaded and automatically extracted to your Downloads folder.</p>
<p>Update will be downloaded to your Downloads folder.</p>
<p className="text-xs text-amber-600">
After download, move the Goose app to /Applications to complete the update.
After download, extract Goose-{updateInfo.latestVersion}.zip and move the Goose app
to /Applications to complete the update.
</p>
</div>
)}
Expand Down
55 changes: 3 additions & 52 deletions ui/desktop/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,22 +44,10 @@ import {
} from './utils/autoUpdater';
import { UPDATES_ENABLED } from './updates';

// Updater toggle functions (moved here to keep updates.ts minimal for release replacement)
let updatesEnabled = UPDATES_ENABLED;

function toggleUpdates(): boolean {
updatesEnabled = !updatesEnabled;
return updatesEnabled;
}

function getUpdatesEnabled(): boolean {
// Only return the toggle state, ignore ENABLE_DEV_UPDATES for UI visibility
return updatesEnabled;
}

// Updater functions (moved here to keep updates.ts minimal for release replacement)
function shouldSetupUpdater(): boolean {
// Setup updater if either the toggle is enabled OR dev updates are enabled
return updatesEnabled || process.env.ENABLE_DEV_UPDATES === 'true';
// Setup updater if either the flag is enabled OR dev updates are enabled
return UPDATES_ENABLED || process.env.ENABLE_DEV_UPDATES === 'true';
}

// Define temp directory for pasted images
Expand Down Expand Up @@ -1222,38 +1210,6 @@ app.whenReady().then(async () => {
// Register the default global hotkey
registerGlobalHotkey('CommandOrControl+Alt+Shift+G');

// Register hidden key combination to toggle updater (Cmd+Shift+U+P+D+A+T+E)
globalShortcut.register('CommandOrControl+Shift+U', () => {
// This is a multi-key sequence, we'll use a simpler approach
// Register a hidden key combination: Cmd/Ctrl + Alt + Shift + U for "Update toggle"
const newState = toggleUpdates();
log.info(
`Updater toggled via keyboard shortcut. New state: ${newState ? 'ENABLED' : 'DISABLED'}`
);

// Show a notification to the user
new Notification({
title: 'Goose Updater',
body: `Updates ${newState ? 'enabled' : 'disabled'}`,
}).show();

// If we're enabling updates and haven't set up the auto-updater yet, set it up now
if (newState) {
try {
setupAutoUpdater(tray || undefined);
log.info('Auto-updater setup completed after keyboard toggle');
} catch (error) {
log.error('Error setting up auto-updater after keyboard toggle:', error);
}
}

// Notify all windows about the updater state change
const windows = BrowserWindow.getAllWindows();
windows.forEach((win) => {
win.webContents.send('updater-state-changed', newState);
});
});

session.defaultSession.webRequest.onBeforeSendHeaders((details, callback) => {
details.requestHeaders['Origin'] = 'http://localhost:5173';
callback({ cancel: false, requestHeaders: details.requestHeaders });
Expand Down Expand Up @@ -1664,11 +1620,6 @@ app.whenReady().then(async () => {
ipcMain.on('get-app-version', (event) => {
event.returnValue = app.getVersion();
});

// Handler for getting updater state
ipcMain.handle('get-updater-enabled', () => {
return getUpdatesEnabled();
});
});

/**
Expand Down
26 changes: 0 additions & 26 deletions ui/desktop/src/preload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,23 +89,13 @@ type ElectronAPI = {
restartApp: () => void;
onUpdaterEvent: (callback: (event: UpdaterEvent) => void) => void;
getUpdateState: () => Promise<{ updateAvailable: boolean; latestVersion?: string } | null>;
// Updater state functions
getUpdaterEnabled: () => Promise<boolean>;
onUpdaterStateChanged: (callback: (enabled: boolean) => void) => void;
removeUpdaterStateListener: (callback: (enabled: boolean) => void) => void;
};

type AppConfigAPI = {
get: (key: string) => unknown;
getAll: () => Record<string, unknown>;
};

// Store callback wrappers for proper cleanup
const updaterStateCallbacks = new Map<
(enabled: boolean) => void,
(event: Electron.IpcRendererEvent, enabled: boolean) => void
>();

const electronAPI: ElectronAPI = {
platform: process.platform,
reactReady: () => ipcRenderer.send('react-ready'),
Expand Down Expand Up @@ -193,22 +183,6 @@ const electronAPI: ElectronAPI = {
getUpdateState: (): Promise<{ updateAvailable: boolean; latestVersion?: string } | null> => {
return ipcRenderer.invoke('get-update-state');
},
// Updater state functions
getUpdaterEnabled: (): Promise<boolean> => {
return ipcRenderer.invoke('get-updater-enabled');
},
onUpdaterStateChanged: (callback: (enabled: boolean) => void): void => {
const wrapper = (_event: Electron.IpcRendererEvent, enabled: boolean) => callback(enabled);
updaterStateCallbacks.set(callback, wrapper);
ipcRenderer.on('updater-state-changed', wrapper);
},
removeUpdaterStateListener: (callback: (enabled: boolean) => void): void => {
const wrapper = updaterStateCallbacks.get(callback);
if (wrapper) {
ipcRenderer.off('updater-state-changed', wrapper);
updaterStateCallbacks.delete(callback);
}
},
};

const appConfigAPI: AppConfigAPI = {
Expand Down
2 changes: 1 addition & 1 deletion ui/desktop/src/updates.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export const UPDATES_ENABLED = false;
export const UPDATES_ENABLED = true;
11 changes: 3 additions & 8 deletions ui/desktop/src/utils/autoUpdater.ts
Original file line number Diff line number Diff line change
Expand Up @@ -201,16 +201,11 @@ export function registerUpdateIpcHandlers() {
}

// Show dialog to inform user about manual installation
const isExtracted = !!githubUpdateInfo.extractedPath;
const dialogResult = (await dialog.showMessageBox({
type: 'info',
title: 'Update Ready',
message: isExtracted
? 'The update has been downloaded and extracted to your Downloads folder.'
: 'The update has been downloaded to your Downloads folder.',
detail: isExtracted
? `Please move the Goose app from ${path.basename(updatePath)} to your Applications folder to complete the update.`
: `Please extract ${path.basename(updatePath)} and move the Goose app to your Applications folder to complete the update.`,
title: 'Update Downloaded',
message: 'The update has been downloaded to your Downloads folder.',
detail: `Please extract ${path.basename(updatePath)} and move the Goose app to your Applications folder to complete the update.`,
buttons: ['Open Downloads', 'Cancel'],
defaultId: 0,
cancelId: 1,
Expand Down
Loading
Loading