diff --git a/electron/main.ts b/electron/main.ts index afa1c01..ca16b0a 100644 --- a/electron/main.ts +++ b/electron/main.ts @@ -69,67 +69,78 @@ async function checkRepos() { let reposUpdated = false; - for (const repo of repos) { - try { - const git = simpleGit(repo.path) - - // Auto-detect remote URL if missing - if (!repo.githubUrl) { - const remotes = await git.getRemotes(true); - const origin = remotes.find(r => r.name === 'origin') || remotes[0]; - if (origin) { - repo.githubUrl = convertGitUrlToHttps(origin.refs.fetch); - reposUpdated = true; + // Prevent concurrent checks to avoid git lock issues + if ((global as any).isCheckingRepos) { + console.log('Skipping checkRepos: previous check still in progress'); + return; + } + (global as any).isCheckingRepos = true; + + try { + for (const repo of repos) { + try { + const git = simpleGit(repo.path) + + // Auto-detect remote URL if missing + if (!repo.githubUrl) { + const remotes = await git.getRemotes(true); + const origin = remotes.find(r => r.name === 'origin') || remotes[0]; + if (origin) { + repo.githubUrl = convertGitUrlToHttps(origin.refs.fetch); + reposUpdated = true; + } } - } - await git.fetch() - const status = await git.status() - - const updateData: any = { - id: repo.id, - status: 'clean', - commitsBehind: 0, - commitsAhead: 0, - githubUrl: repo.githubUrl - }; - - if (status.isClean() === false) { - updateData.status = 'dirty'; - } else if (status.ahead > 0 && status.behind > 0) { - updateData.status = 'diverged'; - updateData.commitsBehind = status.behind; - updateData.commitsAhead = status.ahead; - } else if (status.behind > 0) { - updateData.status = 'behind'; - updateData.commitsBehind = status.behind; - - if (repo.autoPull) { - await git.pull() - notifyUser(repo.name, `Pulled ${status.behind} new commits.`) - updateData.status = 'clean'; - updateData.commitsBehind = 0; - } else { - notifyUser(repo.name, `${status.behind} commits waiting.`, true) + await git.fetch() + const status = await git.status() + + const updateData: any = { + id: repo.id, + status: 'clean', + commitsBehind: 0, + commitsAhead: 0, + githubUrl: repo.githubUrl + }; + + if (status.isClean() === false) { + updateData.status = 'dirty'; + } else if (status.ahead > 0 && status.behind > 0) { + updateData.status = 'diverged'; + updateData.commitsBehind = status.behind; + updateData.commitsAhead = status.ahead; + } else if (status.behind > 0) { + updateData.status = 'behind'; + updateData.commitsBehind = status.behind; + + if (repo.autoPull) { + await git.pull() + notifyUser(repo.name, `Pulled ${status.behind} new commits.`) + updateData.status = 'clean'; + updateData.commitsBehind = 0; + } else { + notifyUser(repo.name, `${status.behind} commits waiting.`, true) + } + } else if (status.ahead > 0) { + updateData.status = 'ahead'; + updateData.commitsAhead = status.ahead; + } + + if (mainWindow && !mainWindow.isDestroyed()) mainWindow.webContents.send('repo-update', updateData) + + } catch (err: any) { + console.error(`Error checking ${repo.name}:`, err) + if (mainWindow && !mainWindow.isDestroyed()) { + mainWindow.webContents.send('repo-error', { id: repo.id, message: err.message || 'Unknown error' }) + mainWindow.webContents.send('repo-update', { id: repo.id, status: 'error' }) } - } else if (status.ahead > 0) { - updateData.status = 'ahead'; - updateData.commitsAhead = status.ahead; - } - - if (mainWindow && !mainWindow.isDestroyed()) mainWindow.webContents.send('repo-update', updateData) - - } catch (err: any) { - console.error(`Error checking ${repo.name}:`, err) - if (mainWindow && !mainWindow.isDestroyed()) { - mainWindow.webContents.send('repo-error', { id: repo.id, message: err.message || 'Unknown error' }) - mainWindow.webContents.send('repo-update', { id: repo.id, status: 'error' }) } } - } - if (reposUpdated) { - store.set('repos', repos); + if (reposUpdated) { + store.set('repos', repos); + } + } finally { + (global as any).isCheckingRepos = false; } } @@ -218,15 +229,18 @@ function createWindow(): void { sandbox: false, nodeIntegration: false, contextIsolation: true, - devTools: true + devTools: true, + webSecurity: app.isPackaged ? false : true, // Relax security for portable builds to avoid "Not allowed to load local resource" + allowRunningInsecureContent: true } }) // LOGGING DIAGNOSTICS - mainWindow.webContents.on('did-fail-load', (event, errorCode, errorDescription) => { - console.error('FAILED TO LOAD:', errorCode, errorDescription); + mainWindow.webContents.on('did-fail-load', (event, errorCode, errorDescription, validatedURL) => { + const msg = `FAILED TO LOAD: ${errorCode} - ${errorDescription} - URL: ${validatedURL}`; + console.error(msg); try { - writeFileSync(join(app.getPath('userData'), 'load-error.log'), `Error: ${errorCode} - ${errorDescription}`); + writeFileSync(join(app.getPath('userData'), 'load-error.log'), msg); } catch (e) {} }); @@ -255,7 +269,17 @@ function createWindow(): void { if (process.env.VITE_DEV_SERVER_URL) { mainWindow.loadURL(process.env.VITE_DEV_SERVER_URL) } else { - mainWindow.loadFile(join(DIST_PATH, 'index.html')) + // For portable builds, we need to be careful with paths. + // Explicitly resolve the index.html path. + const indexPath = join(DIST_PATH, 'index.html'); + + // Log for debugging + console.log('Loading index.html from:', indexPath); + + mainWindow.loadFile(indexPath).catch(e => { + console.error('Failed to load file:', e); + try { writeFileSync(join(app.getPath('userData'), 'load-exception.log'), String(e)); } catch {} + }); } mainWindow.webContents.setWindowOpenHandler(({ url }) => { diff --git a/src/Settings.tsx b/src/Settings.tsx index 2b9d5fd..98a328a 100644 --- a/src/Settings.tsx +++ b/src/Settings.tsx @@ -213,21 +213,28 @@ export const Settings = () => {

- Start automatically on login. + Automatically launch Git Watcher Pro when you sign in.

- { - setLaunchAtStartup(checked === true); - handleSave({ launchAtStartup: checked === true }); - }} - /> +
+ {launchAtStartup && ( + + Enabled + + )} + { + setLaunchAtStartup(checked === true); + handleSave({ launchAtStartup: checked === true }); + }} + /> +
{/* Row 3: Minimize */} diff --git a/verification/settings_page.png b/verification/settings_page.png new file mode 100644 index 0000000..0f14a7d Binary files /dev/null and b/verification/settings_page.png differ diff --git a/verification/verify_settings.py b/verification/verify_settings.py new file mode 100644 index 0000000..b2b585a --- /dev/null +++ b/verification/verify_settings.py @@ -0,0 +1,31 @@ +from playwright.sync_api import sync_playwright, expect +import time + +def run(): + with sync_playwright() as p: + browser = p.chromium.launch(headless=True) + # Use the preview port + page = browser.new_page() + try: + page.goto("http://localhost:4173") + # Wait for content to load + page.wait_for_selector("text=Dashboard", state="visible") + + # Click settings + page.click("text=Settings") + + # Verify the new "Start on System Login" text is present + expect(page.get_by_text("Start on System Login")).to_be_visible() + expect(page.get_by_text("Automatically launch Git Watcher Pro when you sign in.")).to_be_visible() + + # Take screenshot + page.screenshot(path="verification/settings_page.png") + print("Screenshot taken") + except Exception as e: + print(f"Error: {e}") + page.screenshot(path="verification/error.png") + finally: + browser.close() + +if __name__ == "__main__": + run()