feat(desktop 0.1.5): show version + Check for updates in Settings (#12)
- Settings now shows 'Biz Connect for Desktop · Version x.y.z' with a Check for updates button (desktop only, feature-detected). - preload exposes checkForUpdates(); main.js adds the check-updates IPC (returns available/current/dev/error) and, when a build finishes downloading, shows a Restart now / Later dialog instead of only the silent on-next-launch install. - desktop version bumped 0.1.4 -> 0.1.5. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -35,6 +35,17 @@ ipcMain.on('get-install-info', (e) => {
|
|||||||
// on the next restart. No-op in dev (unpackaged).
|
// on the next restart. No-op in dev (unpackaged).
|
||||||
let autoUpdater = null;
|
let autoUpdater = null;
|
||||||
try { ({ autoUpdater } = require('electron-updater')); } catch (_) { /* not installed in dev */ }
|
try { ({ autoUpdater } = require('electron-updater')); } catch (_) { /* not installed in dev */ }
|
||||||
|
// #12: manual "Check for updates" from Settings. Returns the current status; the background updater
|
||||||
|
// (configured in app.whenReady) downloads and prompts to restart when a build is ready.
|
||||||
|
ipcMain.handle('check-updates', async () => {
|
||||||
|
const current = app.getVersion();
|
||||||
|
if (!app.isPackaged || !autoUpdater) return { status: 'dev', current };
|
||||||
|
try {
|
||||||
|
const r = await autoUpdater.checkForUpdates();
|
||||||
|
const v = r && r.updateInfo && r.updateInfo.version;
|
||||||
|
return (v && v !== current) ? { status: 'available', version: v, current } : { status: 'current', current };
|
||||||
|
} catch (e) { return { status: 'error', message: String((e && e.message) || e), current }; }
|
||||||
|
});
|
||||||
// Chat toast: sender/group avatar + message; clicking it raises the app and opens that chat.
|
// Chat toast: sender/group avatar + message; clicking it raises the app and opens that chat.
|
||||||
// Uses Electron's OWN Notification (native, no SnoreToast) whose 'click' event fires reliably.
|
// Uses Electron's OWN Notification (native, no SnoreToast) whose 'click' event fires reliably.
|
||||||
const APP_ID = 'com.bizgaze.connect.desktop';
|
const APP_ID = 'com.bizgaze.connect.desktop';
|
||||||
@@ -205,6 +216,21 @@ app.whenReady().then(() => {
|
|||||||
app.on('activate', () => { if (BrowserWindow.getAllWindows().length === 0) createWindow(); });
|
app.on('activate', () => { if (BrowserWindow.getAllWindows().length === 0) createWindow(); });
|
||||||
// Check for shell updates on launch, then every 6 hours. Only in packaged builds.
|
// Check for shell updates on launch, then every 6 hours. Only in packaged builds.
|
||||||
if (app.isPackaged && autoUpdater) {
|
if (app.isPackaged && autoUpdater) {
|
||||||
|
// When an update finishes downloading (auto or via the Settings "Check for updates"), offer a
|
||||||
|
// clear restart prompt instead of only the silent on-next-launch install.
|
||||||
|
let promptedForUpdate = false;
|
||||||
|
autoUpdater.on('update-downloaded', async (info) => {
|
||||||
|
if (promptedForUpdate) return; promptedForUpdate = true;
|
||||||
|
try {
|
||||||
|
const { dialog } = require('electron');
|
||||||
|
const res = await dialog.showMessageBox(win || undefined, {
|
||||||
|
type: 'info', buttons: ['Restart now', 'Later'], defaultId: 0, cancelId: 1,
|
||||||
|
title: 'Update ready', message: 'Biz Connect ' + ((info && info.version) || '') + ' is ready.',
|
||||||
|
detail: 'Restart the app to finish updating.',
|
||||||
|
});
|
||||||
|
if (res.response === 0) autoUpdater.quitAndInstall();
|
||||||
|
} catch (_) { /* fall back to install-on-next-launch */ }
|
||||||
|
});
|
||||||
const check = () => autoUpdater.checkForUpdatesAndNotify().catch(() => {});
|
const check = () => autoUpdater.checkForUpdatesAndNotify().catch(() => {});
|
||||||
check();
|
check();
|
||||||
setInterval(check, 6 * 60 * 60 * 1000);
|
setInterval(check, 6 * 60 * 60 * 1000);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "biz-connect-desktop",
|
"name": "biz-connect-desktop",
|
||||||
"version": "0.1.4",
|
"version": "0.1.5",
|
||||||
"description": "Biz Connect technician desktop client — loads the Connect web UI with native screen capture",
|
"description": "Biz Connect technician desktop client — loads the Connect web UI with native screen capture",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "BizGaze",
|
"name": "BizGaze",
|
||||||
|
|||||||
@@ -22,4 +22,7 @@ contextBridge.exposeInMainWorld('bizConnectNative', Object.freeze({
|
|||||||
// Native Windows toast with an inline reply box. Resolves to {text} (replied), {open} (clicked)
|
// Native Windows toast with an inline reply box. Resolves to {text} (replied), {open} (clicked)
|
||||||
// or null. Lets the user reply to a chat straight from the notification.
|
// or null. Lets the user reply to a chat straight from the notification.
|
||||||
replyNotify: (payload) => ipcRenderer.invoke('reply-notification', payload),
|
replyNotify: (payload) => ipcRenderer.invoke('reply-notification', payload),
|
||||||
|
// Manual "Check for updates" from Settings. Resolves {status:'available'|'current'|'dev'|'error', version?}.
|
||||||
|
// On 'available' the shell downloads in the background and prompts to restart when ready.
|
||||||
|
checkForUpdates: () => ipcRenderer.invoke('check-updates'),
|
||||||
}));
|
}));
|
||||||
|
|||||||
+16
-1
@@ -809,7 +809,7 @@
|
|||||||
<body>
|
<body>
|
||||||
<script src="/icons.js?v=4"></script>
|
<script src="/icons.js?v=4"></script>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/@twemoji/api@15.1.0/dist/twemoji.min.js" crossorigin="anonymous"></script>
|
<script src="https://cdn.jsdelivr.net/npm/@twemoji/api@15.1.0/dist/twemoji.min.js" crossorigin="anonymous"></script>
|
||||||
<script>window.__BUILD='2026-07-07-batch50';console.log('%cBiz Connect','color:#1F3B73;font-weight:bold','build '+window.__BUILD);
|
<script>window.__BUILD='2026-07-07-batch51';console.log('%cBiz Connect','color:#1F3B73;font-weight:bold','build '+window.__BUILD);
|
||||||
// Render modern (Twemoji) emojis in place of the OS's flat ones. No-op if the CDN didn't load
|
// Render modern (Twemoji) emojis in place of the OS's flat ones. No-op if the CDN didn't load
|
||||||
// (emojis stay as plain Unicode). (#5)
|
// (emojis stay as plain Unicode). (#5)
|
||||||
function twemojify(el){ try{ if(el && window.twemoji) window.twemoji.parse(el, { folder:'svg', ext:'.svg' }); }catch(_){} }</script>
|
function twemojify(el){ try{ if(el && window.twemoji) window.twemoji.parse(el, { folder:'svg', ext:'.svg' }); }catch(_){} }</script>
|
||||||
@@ -986,10 +986,25 @@ function openSettings(){
|
|||||||
+sw('setGroup','Group message notifications', notifOn('group'))
|
+sw('setGroup','Group message notifications', notifOn('group'))
|
||||||
+sw('setDm','Direct message notifications', notifOn('dm'))
|
+sw('setDm','Direct message notifications', notifOn('dm'))
|
||||||
+'<label class="gi-setting"><span>Notifications <span class="perm-state '+perm+'">'+permLabel+'</span><div style="font-size:.72rem;color:var(--muted);font-weight:400;margin-top:.15rem">Pop up messages & calls even when this tab isn’t open</div></span>'+(granted?'':'<button class="btn sm" id="setPerm">'+(perm==='denied'?'Allow':'Enable')+'</button>')+'</label>'
|
+'<label class="gi-setting"><span>Notifications <span class="perm-state '+perm+'">'+permLabel+'</span><div style="font-size:.72rem;color:var(--muted);font-weight:400;margin-top:.15rem">Pop up messages & calls even when this tab isn’t open</div></span>'+(granted?'':'<button class="btn sm" id="setPerm">'+(perm==='denied'?'Allow':'Enable')+'</button>')+'</label>'
|
||||||
|
+(window.bizConnectNative?('<label class="gi-setting"><span>Biz Connect for Desktop<div style="font-size:.72rem;color:var(--muted);font-weight:400;margin-top:.15rem" id="setVer">Version '+pEsc(window.bizConnectNative.version||'—')+'</div></span><button class="btn sm" id="setUpd">Check for updates</button></label>'):'')
|
||||||
+'<div class="hint" style="margin-top:.4rem">These preferences are saved on this device.</div></div>';
|
+'<div class="hint" style="margin-top:.4rem">These preferences are saved on this device.</div></div>';
|
||||||
document.body.appendChild(ov);
|
document.body.appendChild(ov);
|
||||||
ov.onclick=e=>{ if(e.target===ov) ov.remove(); };
|
ov.onclick=e=>{ if(e.target===ov) ov.remove(); };
|
||||||
ov.querySelector('#setClose').onclick=()=>ov.remove();
|
ov.querySelector('#setClose').onclick=()=>ov.remove();
|
||||||
|
const updBtn=ov.querySelector('#setUpd'); // #12: desktop version + manual update check
|
||||||
|
if(updBtn) updBtn.onclick=async()=>{
|
||||||
|
const ver=ov.querySelector('#setVer'); updBtn.disabled=true; updBtn.textContent='Checking…';
|
||||||
|
let done=false;
|
||||||
|
try{
|
||||||
|
const r=(window.bizConnectNative&&window.bizConnectNative.checkForUpdates)?await window.bizConnectNative.checkForUpdates():{status:'unsupported'};
|
||||||
|
if(r.status==='available'){ updBtn.textContent='Update '+(r.version||'')+' found'; if(ver) ver.textContent='Downloading '+(r.version||'')+'… you’ll be asked to restart when ready.'; done=true; }
|
||||||
|
else if(r.status==='current'){ updBtn.textContent='Up to date ✓'; }
|
||||||
|
else if(r.status==='dev'){ updBtn.textContent='Dev build'; }
|
||||||
|
else if(r.status==='unsupported'){ updBtn.textContent='Update on newer app'; }
|
||||||
|
else { updBtn.textContent='Check failed'; }
|
||||||
|
}catch(_){ updBtn.textContent='Check failed'; }
|
||||||
|
setTimeout(()=>{ if(!done){ updBtn.disabled=false; updBtn.textContent='Check for updates'; } }, 3500);
|
||||||
|
};
|
||||||
const setPref=(k,v)=>{ try{ localStorage.setItem('notif_'+k, v?'on':'off'); }catch(_){} };
|
const setPref=(k,v)=>{ try{ localStorage.setItem('notif_'+k, v?'on':'off'); }catch(_){} };
|
||||||
ov.querySelector('#setGroup').onchange=e=>setPref('group', e.target.checked);
|
ov.querySelector('#setGroup').onchange=e=>setPref('group', e.target.checked);
|
||||||
ov.querySelector('#setDm').onchange=e=>setPref('dm', e.target.checked);
|
ov.querySelector('#setDm').onchange=e=>setPref('dm', e.target.checked);
|
||||||
|
|||||||
Reference in New Issue
Block a user