Add self-update feature via GitHub Releases
Checks for updates on startup (silent, badge on button if available) and on manual click. Downloads new portable .exe to temp dir, creates a batch script to swap the running executable after quit, then relaunches. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
+140
@@ -21,10 +21,23 @@ const cookieKey = document.getElementById('cookieKey');
|
||||
const startCookieProxyBtn = document.getElementById('startCookieProxyBtn');
|
||||
const stopCookieProxyBtn = document.getElementById('stopCookieProxyBtn');
|
||||
|
||||
// Update elements
|
||||
const checkUpdateBtn = document.getElementById('checkUpdateBtn');
|
||||
const updateModalOverlay = document.getElementById('updateModalOverlay');
|
||||
const updateModalCloseBtn = document.getElementById('updateModalCloseBtn');
|
||||
const updateModalMessage = document.getElementById('updateModalMessage');
|
||||
const updateModalNotes = document.getElementById('updateModalNotes');
|
||||
const updateProgressContainer = document.getElementById('updateProgressContainer');
|
||||
const updateProgressFill = document.getElementById('updateProgressFill');
|
||||
const updateProgressText = document.getElementById('updateProgressText');
|
||||
const updateInstallBtn = document.getElementById('updateInstallBtn');
|
||||
const updateLaterBtn = document.getElementById('updateLaterBtn');
|
||||
|
||||
// Track selected device
|
||||
let selectedDevice = null;
|
||||
let activeCookieProxyConnections = new Map(); // Track cookie-based proxy connections
|
||||
let allDevices = []; // Store all devices for search functionality
|
||||
let pendingUpdateInfo = null; // Store update info for install action
|
||||
|
||||
// Event listeners
|
||||
disconnectBtn.addEventListener('click', handleDisconnect);
|
||||
@@ -39,6 +52,12 @@ cookieKey.addEventListener('input', updateCookieProxyButtonStates);
|
||||
// Device search event listener
|
||||
deviceSearch.addEventListener('input', handleDeviceSearch);
|
||||
|
||||
// Update event listeners
|
||||
checkUpdateBtn.addEventListener('click', handleCheckForUpdates);
|
||||
updateInstallBtn.addEventListener('click', handleInstallUpdate);
|
||||
updateLaterBtn.addEventListener('click', closeUpdateModal);
|
||||
updateModalCloseBtn.addEventListener('click', closeUpdateModal);
|
||||
|
||||
// Handle disconnect
|
||||
function handleDisconnect() {
|
||||
sessionData.isConnected = false;
|
||||
@@ -432,6 +451,118 @@ function escapeHtml(text) {
|
||||
return div.innerHTML;
|
||||
}
|
||||
|
||||
// --- Self-Update Functions ---
|
||||
|
||||
async function handleCheckForUpdates() {
|
||||
checkUpdateBtn.disabled = true;
|
||||
|
||||
try {
|
||||
const result = await window.electronAPI.checkForUpdates();
|
||||
|
||||
if (!result.success) {
|
||||
showStatus(connectionStatus, result.message || 'Failed to check for updates', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
if (result.message === 'No releases available yet') {
|
||||
showStatus(connectionStatus, 'No releases available yet', 'info');
|
||||
return;
|
||||
}
|
||||
|
||||
if (result.updateAvailable) {
|
||||
showUpdateModal(result);
|
||||
} else {
|
||||
showStatus(connectionStatus, `You're on the latest version (v${result.currentVersion})`, 'success');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Check for updates error:', error);
|
||||
showStatus(connectionStatus, 'Could not check for updates. Check your internet connection.', 'error');
|
||||
} finally {
|
||||
checkUpdateBtn.disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
function showUpdateModal(updateInfo) {
|
||||
pendingUpdateInfo = updateInfo;
|
||||
updateModalMessage.textContent = `A new version is available: v${updateInfo.latestVersion} (current: v${updateInfo.currentVersion})`;
|
||||
updateModalNotes.textContent = updateInfo.releaseNotes || '';
|
||||
|
||||
// Reset progress state
|
||||
updateProgressContainer.style.display = 'none';
|
||||
updateProgressFill.style.width = '0%';
|
||||
updateProgressText.textContent = '0%';
|
||||
|
||||
// Reset button states
|
||||
updateInstallBtn.disabled = !updateInfo.downloadUrl;
|
||||
updateLaterBtn.disabled = false;
|
||||
updateInstallBtn.textContent = 'Install Update';
|
||||
|
||||
if (!updateInfo.downloadUrl) {
|
||||
updateModalMessage.textContent += '\n(No downloadable asset found for this release)';
|
||||
}
|
||||
|
||||
updateModalOverlay.style.display = 'flex';
|
||||
}
|
||||
|
||||
async function handleInstallUpdate() {
|
||||
if (!pendingUpdateInfo || !pendingUpdateInfo.downloadUrl) return;
|
||||
|
||||
// Disable controls during download
|
||||
updateInstallBtn.disabled = true;
|
||||
updateInstallBtn.textContent = 'Downloading...';
|
||||
updateLaterBtn.disabled = true;
|
||||
updateModalCloseBtn.style.display = 'none';
|
||||
updateProgressContainer.style.display = 'flex';
|
||||
|
||||
try {
|
||||
const result = await window.electronAPI.downloadAndInstallUpdate({
|
||||
downloadUrl: pendingUpdateInfo.downloadUrl
|
||||
});
|
||||
|
||||
if (result.success) {
|
||||
updateInstallBtn.textContent = 'Restarting...';
|
||||
updateProgressFill.style.width = '100%';
|
||||
updateProgressText.textContent = '100%';
|
||||
} else {
|
||||
showStatus(connectionStatus, `Update failed: ${result.message}`, 'error');
|
||||
closeUpdateModal();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Install update error:', error);
|
||||
showStatus(connectionStatus, 'Update failed. Please try again.', 'error');
|
||||
closeUpdateModal();
|
||||
}
|
||||
}
|
||||
|
||||
function closeUpdateModal() {
|
||||
updateModalOverlay.style.display = 'none';
|
||||
pendingUpdateInfo = null;
|
||||
updateProgressContainer.style.display = 'none';
|
||||
updateProgressFill.style.width = '0%';
|
||||
updateProgressText.textContent = '0%';
|
||||
updateInstallBtn.textContent = 'Install Update';
|
||||
updateInstallBtn.disabled = false;
|
||||
updateLaterBtn.disabled = false;
|
||||
updateModalCloseBtn.style.display = '';
|
||||
}
|
||||
|
||||
async function checkForUpdatesOnStartup() {
|
||||
try {
|
||||
const result = await window.electronAPI.checkForUpdates();
|
||||
|
||||
if (result.success && result.updateAvailable) {
|
||||
checkUpdateBtn.classList.add('update-available');
|
||||
checkUpdateBtn.title = `Update available: v${result.latestVersion}`;
|
||||
showStatus(connectionStatus, `Update available: v${result.latestVersion}`, 'info');
|
||||
// Store for quick modal open
|
||||
pendingUpdateInfo = result;
|
||||
}
|
||||
} catch (error) {
|
||||
// Silent fail on startup check
|
||||
console.log('Startup update check failed:', error.message);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle cookie received from Chrome extension via local HTTP bridge
|
||||
async function handleExtensionCookie(data) {
|
||||
const { deploymentUrl, cookies, cookieValue } = data;
|
||||
@@ -473,4 +604,13 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
|
||||
// Listen for cookies pushed from Chrome extension
|
||||
window.electronAPI.onExtensionCookie(handleExtensionCookie);
|
||||
|
||||
// Listen for update download progress
|
||||
window.electronAPI.onUpdateDownloadProgress((data) => {
|
||||
updateProgressFill.style.width = `${data.percent}%`;
|
||||
updateProgressText.textContent = `${data.percent}%`;
|
||||
});
|
||||
|
||||
// Auto-check for updates after 2 seconds
|
||||
setTimeout(checkForUpdatesOnStartup, 2000);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user