mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-06-28 21:49:40 +02:00
refactor(desktop): extract window creation into modules/window.ts
This commit is contained in:
parent
f08199ecec
commit
95c4a674be
2 changed files with 80 additions and 68 deletions
|
|
@ -1,72 +1,16 @@
|
||||||
import { app, BrowserWindow, shell, ipcMain, session, dialog, Menu } from 'electron';
|
import { app, BrowserWindow, shell, ipcMain, dialog, Menu } from 'electron';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { autoUpdater } from 'electron-updater';
|
import { autoUpdater } from 'electron-updater';
|
||||||
import { registerGlobalErrorHandlers, showErrorDialog } from './modules/errors';
|
import { registerGlobalErrorHandlers, showErrorDialog } from './modules/errors';
|
||||||
import { startNextServer, getServerPort } from './modules/server';
|
import { startNextServer, getServerPort } from './modules/server';
|
||||||
|
import { createMainWindow, getMainWindow } from './modules/window';
|
||||||
|
|
||||||
registerGlobalErrorHandlers();
|
registerGlobalErrorHandlers();
|
||||||
|
|
||||||
const isDev = !app.isPackaged;
|
const isDev = !app.isPackaged;
|
||||||
let mainWindow: BrowserWindow | null = null;
|
|
||||||
let deepLinkUrl: string | null = null;
|
let deepLinkUrl: string | null = null;
|
||||||
|
|
||||||
const PROTOCOL = 'surfsense';
|
const PROTOCOL = 'surfsense';
|
||||||
const HOSTED_FRONTEND_URL = process.env.HOSTED_FRONTEND_URL as string;
|
|
||||||
|
|
||||||
function createWindow() {
|
|
||||||
mainWindow = new BrowserWindow({
|
|
||||||
width: 1280,
|
|
||||||
height: 800,
|
|
||||||
minWidth: 800,
|
|
||||||
minHeight: 600,
|
|
||||||
webPreferences: {
|
|
||||||
preload: path.join(__dirname, 'preload.js'),
|
|
||||||
contextIsolation: true,
|
|
||||||
nodeIntegration: false,
|
|
||||||
sandbox: true,
|
|
||||||
webviewTag: false,
|
|
||||||
},
|
|
||||||
show: false,
|
|
||||||
titleBarStyle: 'hiddenInset',
|
|
||||||
});
|
|
||||||
|
|
||||||
mainWindow.once('ready-to-show', () => {
|
|
||||||
mainWindow?.show();
|
|
||||||
});
|
|
||||||
|
|
||||||
mainWindow.loadURL(`http://localhost:${getServerPort()}/login`);
|
|
||||||
|
|
||||||
// External links open in system browser, not in the Electron window
|
|
||||||
mainWindow.webContents.setWindowOpenHandler(({ url }) => {
|
|
||||||
if (url.startsWith('http://localhost')) {
|
|
||||||
return { action: 'allow' };
|
|
||||||
}
|
|
||||||
shell.openExternal(url);
|
|
||||||
return { action: 'deny' };
|
|
||||||
});
|
|
||||||
|
|
||||||
// Intercept backend OAuth redirects targeting the hosted web frontend
|
|
||||||
// and rewrite them to localhost so the user stays in the desktop app.
|
|
||||||
const filter = { urls: [`${HOSTED_FRONTEND_URL}/*`] };
|
|
||||||
session.defaultSession.webRequest.onBeforeRequest(filter, (details, callback) => {
|
|
||||||
const rewritten = details.url.replace(HOSTED_FRONTEND_URL, `http://localhost:${getServerPort()}`);
|
|
||||||
callback({ redirectURL: rewritten });
|
|
||||||
});
|
|
||||||
|
|
||||||
mainWindow.webContents.on('did-fail-load', (_event, errorCode, errorDescription, validatedURL) => {
|
|
||||||
console.error(`Failed to load ${validatedURL}: ${errorDescription} (${errorCode})`);
|
|
||||||
if (errorCode === -3) return; // ERR_ABORTED — normal during redirects
|
|
||||||
showErrorDialog('Page failed to load', new Error(`${errorDescription} (${errorCode})\n${validatedURL}`));
|
|
||||||
});
|
|
||||||
|
|
||||||
if (isDev) {
|
|
||||||
mainWindow.webContents.openDevTools();
|
|
||||||
}
|
|
||||||
|
|
||||||
mainWindow.on('closed', () => {
|
|
||||||
mainWindow = null;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// IPC handlers
|
// IPC handlers
|
||||||
ipcMain.on('open-external', (_event, url: string) => {
|
ipcMain.on('open-external', (_event, url: string) => {
|
||||||
|
|
@ -90,17 +34,17 @@ function handleDeepLink(url: string) {
|
||||||
|
|
||||||
deepLinkUrl = url;
|
deepLinkUrl = url;
|
||||||
|
|
||||||
if (!mainWindow) return;
|
const win = getMainWindow();
|
||||||
|
if (!win) return;
|
||||||
|
|
||||||
// Rewrite surfsense:// deep link to localhost so TokenHandler.tsx processes it
|
|
||||||
const parsed = new URL(url);
|
const parsed = new URL(url);
|
||||||
if (parsed.hostname === 'auth' && parsed.pathname === '/callback') {
|
if (parsed.hostname === 'auth' && parsed.pathname === '/callback') {
|
||||||
const params = parsed.searchParams.toString();
|
const params = parsed.searchParams.toString();
|
||||||
mainWindow.loadURL(`http://localhost:${getServerPort()}/auth/callback?${params}`);
|
win.loadURL(`http://localhost:${getServerPort()}/auth/callback?${params}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
mainWindow.show();
|
win.show();
|
||||||
mainWindow.focus();
|
win.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Single instance lock — second instance passes deep link to first
|
// Single instance lock — second instance passes deep link to first
|
||||||
|
|
@ -113,9 +57,10 @@ if (!gotTheLock) {
|
||||||
const url = argv.find((arg) => arg.startsWith(`${PROTOCOL}://`));
|
const url = argv.find((arg) => arg.startsWith(`${PROTOCOL}://`));
|
||||||
if (url) handleDeepLink(url);
|
if (url) handleDeepLink(url);
|
||||||
|
|
||||||
if (mainWindow) {
|
const win = getMainWindow();
|
||||||
if (mainWindow.isMinimized()) mainWindow.restore();
|
if (win) {
|
||||||
mainWindow.focus();
|
if (win.isMinimized()) win.restore();
|
||||||
|
win.focus();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -188,7 +133,7 @@ app.whenReady().then(async () => {
|
||||||
setTimeout(() => app.quit(), 0);
|
setTimeout(() => app.quit(), 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
createWindow();
|
createMainWindow();
|
||||||
setupAutoUpdater();
|
setupAutoUpdater();
|
||||||
|
|
||||||
// If a deep link was received before the window was ready, handle it now
|
// If a deep link was received before the window was ready, handle it now
|
||||||
|
|
@ -199,7 +144,7 @@ app.whenReady().then(async () => {
|
||||||
|
|
||||||
app.on('activate', () => {
|
app.on('activate', () => {
|
||||||
if (BrowserWindow.getAllWindows().length === 0) {
|
if (BrowserWindow.getAllWindows().length === 0) {
|
||||||
createWindow();
|
createMainWindow();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
67
surfsense_desktop/src/modules/window.ts
Normal file
67
surfsense_desktop/src/modules/window.ts
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
import { app, BrowserWindow, shell, session } from 'electron';
|
||||||
|
import path from 'path';
|
||||||
|
import { showErrorDialog } from './errors';
|
||||||
|
import { getServerPort } from './server';
|
||||||
|
|
||||||
|
const isDev = !app.isPackaged;
|
||||||
|
const HOSTED_FRONTEND_URL = process.env.HOSTED_FRONTEND_URL as string;
|
||||||
|
|
||||||
|
let mainWindow: BrowserWindow | null = null;
|
||||||
|
|
||||||
|
export function getMainWindow(): BrowserWindow | null {
|
||||||
|
return mainWindow;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createMainWindow(): BrowserWindow {
|
||||||
|
mainWindow = new BrowserWindow({
|
||||||
|
width: 1280,
|
||||||
|
height: 800,
|
||||||
|
minWidth: 800,
|
||||||
|
minHeight: 600,
|
||||||
|
webPreferences: {
|
||||||
|
preload: path.join(__dirname, 'preload.js'),
|
||||||
|
contextIsolation: true,
|
||||||
|
nodeIntegration: false,
|
||||||
|
sandbox: true,
|
||||||
|
webviewTag: false,
|
||||||
|
},
|
||||||
|
show: false,
|
||||||
|
titleBarStyle: 'hiddenInset',
|
||||||
|
});
|
||||||
|
|
||||||
|
mainWindow.once('ready-to-show', () => {
|
||||||
|
mainWindow?.show();
|
||||||
|
});
|
||||||
|
|
||||||
|
mainWindow.loadURL(`http://localhost:${getServerPort()}/login`);
|
||||||
|
|
||||||
|
mainWindow.webContents.setWindowOpenHandler(({ url }) => {
|
||||||
|
if (url.startsWith('http://localhost')) {
|
||||||
|
return { action: 'allow' };
|
||||||
|
}
|
||||||
|
shell.openExternal(url);
|
||||||
|
return { action: 'deny' };
|
||||||
|
});
|
||||||
|
|
||||||
|
const filter = { urls: [`${HOSTED_FRONTEND_URL}/*`] };
|
||||||
|
session.defaultSession.webRequest.onBeforeRequest(filter, (details, callback) => {
|
||||||
|
const rewritten = details.url.replace(HOSTED_FRONTEND_URL, `http://localhost:${getServerPort()}`);
|
||||||
|
callback({ redirectURL: rewritten });
|
||||||
|
});
|
||||||
|
|
||||||
|
mainWindow.webContents.on('did-fail-load', (_event, errorCode, errorDescription, validatedURL) => {
|
||||||
|
console.error(`Failed to load ${validatedURL}: ${errorDescription} (${errorCode})`);
|
||||||
|
if (errorCode === -3) return;
|
||||||
|
showErrorDialog('Page failed to load', new Error(`${errorDescription} (${errorCode})\n${validatedURL}`));
|
||||||
|
});
|
||||||
|
|
||||||
|
if (isDev) {
|
||||||
|
mainWindow.webContents.openDevTools();
|
||||||
|
}
|
||||||
|
|
||||||
|
mainWindow.on('closed', () => {
|
||||||
|
mainWindow = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
return mainWindow;
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue