Check for updates button in moar menus & toasts (#7369)
* Check for update button in more menus Fixes #7368 * Add menubar item * Another one * Add Checking for updates... and No new update toasts * Lint * Trigger CI * Update src/main.ts Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com> * Update electron-builder.yml Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com> * Update electron-builder.yml * Moar clean up --------- Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
This commit is contained in:
2
interface.d.ts
vendored
2
interface.d.ts
vendored
@ -92,6 +92,8 @@ export interface IElectronAPI {
|
|||||||
kittycad: (access: string, args: any) => any
|
kittycad: (access: string, args: any) => any
|
||||||
listMachines: (machineApiIp: string) => Promise<MachinesListing>
|
listMachines: (machineApiIp: string) => Promise<MachinesListing>
|
||||||
getMachineApiIp: () => Promise<string | null>
|
getMachineApiIp: () => Promise<string | null>
|
||||||
|
onUpdateChecking: (callback: () => void) => Electron.IpcRenderer
|
||||||
|
onUpdateNotAvailable: (callback: () => void) => Electron.IpcRenderer
|
||||||
onUpdateDownloadStart: (
|
onUpdateDownloadStart: (
|
||||||
callback: (value: { version: string }) => void
|
callback: (value: { version: string }) => void
|
||||||
) => Electron.IpcRenderer
|
) => Electron.IpcRenderer
|
||||||
|
@ -14,6 +14,8 @@ import {
|
|||||||
catchOnboardingWarnError,
|
catchOnboardingWarnError,
|
||||||
} from '@src/routes/Onboarding/utils'
|
} from '@src/routes/Onboarding/utils'
|
||||||
import { onboardingStartPath } from '@src/lib/onboardingPaths'
|
import { onboardingStartPath } from '@src/lib/onboardingPaths'
|
||||||
|
import { reportRejection } from '@src/lib/trap'
|
||||||
|
import { isDesktop } from '@src/lib/isDesktop'
|
||||||
|
|
||||||
const HelpMenuDivider = () => (
|
const HelpMenuDivider = () => (
|
||||||
<div className="h-[1px] bg-chalkboard-110 dark:bg-chalkboard-80" />
|
<div className="h-[1px] bg-chalkboard-110 dark:bg-chalkboard-80" />
|
||||||
@ -117,6 +119,17 @@ export function HelpMenu({
|
|||||||
>
|
>
|
||||||
Release notes
|
Release notes
|
||||||
</HelpMenuItem>
|
</HelpMenuItem>
|
||||||
|
{isDesktop() && (
|
||||||
|
<HelpMenuItem
|
||||||
|
as="button"
|
||||||
|
onClick={() => {
|
||||||
|
close()
|
||||||
|
window.electron.appCheckForUpdates().catch(reportRejection)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Check for updates
|
||||||
|
</HelpMenuItem>
|
||||||
|
)}
|
||||||
<HelpMenuItem
|
<HelpMenuItem
|
||||||
as="button"
|
as="button"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
@ -12,6 +12,7 @@ import usePlatform from '@src/hooks/usePlatform'
|
|||||||
import { isDesktop } from '@src/lib/isDesktop'
|
import { isDesktop } from '@src/lib/isDesktop'
|
||||||
import { PATHS } from '@src/lib/paths'
|
import { PATHS } from '@src/lib/paths'
|
||||||
import { authActor } from '@src/lib/singletons'
|
import { authActor } from '@src/lib/singletons'
|
||||||
|
import { reportRejection } from '@src/lib/trap'
|
||||||
|
|
||||||
type User = Models['User_type']
|
type User = Models['User_type']
|
||||||
|
|
||||||
@ -129,6 +130,15 @@ const UserSidebarMenu = ({ user }: { user?: User }) => {
|
|||||||
</>
|
</>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'check-for-updates',
|
||||||
|
Element: 'button',
|
||||||
|
hide: !isDesktop(),
|
||||||
|
onClick: () => {
|
||||||
|
window.electron.appCheckForUpdates().catch(reportRejection)
|
||||||
|
},
|
||||||
|
children: <span className="flex-1">Check for updates</span>,
|
||||||
|
},
|
||||||
'break',
|
'break',
|
||||||
{
|
{
|
||||||
id: 'sign-out',
|
id: 'sign-out',
|
||||||
|
@ -81,21 +81,31 @@ root.render(
|
|||||||
reportWebVitals()
|
reportWebVitals()
|
||||||
|
|
||||||
if (isDesktop()) {
|
if (isDesktop()) {
|
||||||
// Listen for update download progress to begin
|
window.electron.onUpdateChecking(() => {
|
||||||
// to show a loading toast.
|
const message = `Checking for updates...`
|
||||||
|
console.log(message)
|
||||||
|
toast.loading(message, { id: AUTO_UPDATER_TOAST_ID })
|
||||||
|
})
|
||||||
|
|
||||||
|
window.electron.onUpdateNotAvailable(() => {
|
||||||
|
const message = `You're already using the latest version of the app.`
|
||||||
|
console.log(message)
|
||||||
|
toast.success(message, { id: AUTO_UPDATER_TOAST_ID })
|
||||||
|
})
|
||||||
|
|
||||||
window.electron.onUpdateDownloadStart(() => {
|
window.electron.onUpdateDownloadStart(() => {
|
||||||
const message = `Downloading app update...`
|
const message = `Downloading app update...`
|
||||||
console.log(message)
|
console.log(message)
|
||||||
toast.loading(message, { id: AUTO_UPDATER_TOAST_ID })
|
toast.loading(message, { id: AUTO_UPDATER_TOAST_ID })
|
||||||
})
|
})
|
||||||
// Listen for update download errors to show
|
|
||||||
// an error toast and clear the loading toast.
|
|
||||||
window.electron.onUpdateError(({ error }) => {
|
window.electron.onUpdateError(({ error }) => {
|
||||||
console.error(error)
|
console.error(error)
|
||||||
toast.error('An error occurred while downloading the update.', {
|
toast.error('An error occurred while downloading the update.', {
|
||||||
id: AUTO_UPDATER_TOAST_ID,
|
id: AUTO_UPDATER_TOAST_ID,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
window.electron.onUpdateDownloaded(({ version, releaseNotes }) => {
|
window.electron.onUpdateDownloaded(({ version, releaseNotes }) => {
|
||||||
const message = `A new update (${version}) was downloaded and will be available next time you open the app.`
|
const message = `A new update (${version}) was downloaded and will be available next time you open the app.`
|
||||||
console.log(message)
|
console.log(message)
|
||||||
|
47
src/main.ts
47
src/main.ts
@ -19,9 +19,9 @@ import {
|
|||||||
shell,
|
shell,
|
||||||
systemPreferences,
|
systemPreferences,
|
||||||
} from 'electron'
|
} from 'electron'
|
||||||
import electronUpdater, { type AppUpdater } from 'electron-updater'
|
|
||||||
import { Issuer } from 'openid-client'
|
import { Issuer } from 'openid-client'
|
||||||
|
|
||||||
|
import { getAutoUpdater } from '@src/updater'
|
||||||
import {
|
import {
|
||||||
argvFromYargs,
|
argvFromYargs,
|
||||||
getPathOrUrlFromArgs,
|
getPathOrUrlFromArgs,
|
||||||
@ -442,16 +442,6 @@ ipcMain.handle('disable-menu', (event, data) => {
|
|||||||
disableMenu(menuId)
|
disableMenu(menuId)
|
||||||
})
|
})
|
||||||
|
|
||||||
export function getAutoUpdater(): AppUpdater {
|
|
||||||
// Using destructuring to access autoUpdater due to the CommonJS module of 'electron-updater'.
|
|
||||||
// It is a workaround for ESM compatibility issues, see https://github.com/electron-userland/electron-builder/issues/7976.
|
|
||||||
const { autoUpdater } = electronUpdater
|
|
||||||
// Allows us to rollback to a previous version if needed.
|
|
||||||
// See https://github.com/electron-userland/electron-builder/blob/7dbc6c77c340c869d1e7effa22135fc740003a0f/packages/electron-updater/src/AppUpdater.ts#L450-L451
|
|
||||||
autoUpdater.allowDowngrade = true
|
|
||||||
return autoUpdater
|
|
||||||
}
|
|
||||||
|
|
||||||
app.on('ready', () => {
|
app.on('ready', () => {
|
||||||
// Disable auto updater on non-versioned builds
|
// Disable auto updater on non-versioned builds
|
||||||
if (packageJSON.version === '0.0.0' && viteEnv.MODE !== 'production') {
|
if (packageJSON.version === '0.0.0' && viteEnv.MODE !== 'production') {
|
||||||
@ -462,13 +452,36 @@ app.on('ready', () => {
|
|||||||
// TODO: we're getting `Error: Response ends without calling any handlers` with our setup,
|
// TODO: we're getting `Error: Response ends without calling any handlers` with our setup,
|
||||||
// so at the moment this isn't worth enabling
|
// so at the moment this isn't worth enabling
|
||||||
autoUpdater.disableDifferentialDownload = true
|
autoUpdater.disableDifferentialDownload = true
|
||||||
setTimeout(() => {
|
|
||||||
autoUpdater.checkForUpdates().catch(reportRejection)
|
// Check for updates in the background at startup and then every 15 minutes
|
||||||
}, 1000)
|
let backgroundCheckingForUpdates = false
|
||||||
|
const checkForUpdatesBackground = () => {
|
||||||
|
backgroundCheckingForUpdates = true
|
||||||
|
autoUpdater
|
||||||
|
.checkForUpdates()
|
||||||
|
.catch(reportRejection)
|
||||||
|
.finally(() => {
|
||||||
|
backgroundCheckingForUpdates = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const oneSecond = 1000
|
||||||
const fifteenMinutes = 15 * 60 * 1000
|
const fifteenMinutes = 15 * 60 * 1000
|
||||||
setInterval(() => {
|
setTimeout(checkForUpdatesBackground, oneSecond)
|
||||||
autoUpdater.checkForUpdates().catch(reportRejection)
|
setInterval(checkForUpdatesBackground, fifteenMinutes)
|
||||||
}, fifteenMinutes)
|
|
||||||
|
autoUpdater.on('checking-for-update', () => {
|
||||||
|
console.log('checking-for-update')
|
||||||
|
if (!backgroundCheckingForUpdates) {
|
||||||
|
mainWindow?.webContents.send('update-checking')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
autoUpdater.on('update-not-available', (info) => {
|
||||||
|
console.log('update-not-available', info)
|
||||||
|
if (!backgroundCheckingForUpdates) {
|
||||||
|
mainWindow?.webContents.send('update-not-available')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
autoUpdater.on('error', (error) => {
|
autoUpdater.on('error', (error) => {
|
||||||
console.error('update-error', error)
|
console.error('update-error', error)
|
||||||
|
@ -4,6 +4,7 @@ import { shell } from 'electron'
|
|||||||
import { reportRejection } from '@src/lib/trap'
|
import { reportRejection } from '@src/lib/trap'
|
||||||
import { typeSafeWebContentsSend } from '@src/menu/channels'
|
import { typeSafeWebContentsSend } from '@src/menu/channels'
|
||||||
import type { ZooMenuItemConstructorOptions } from '@src/menu/roles'
|
import type { ZooMenuItemConstructorOptions } from '@src/menu/roles'
|
||||||
|
import { getAutoUpdater } from '@src/updater'
|
||||||
|
|
||||||
export const helpRole = (
|
export const helpRole = (
|
||||||
mainWindow: BrowserWindow
|
mainWindow: BrowserWindow
|
||||||
@ -105,6 +106,12 @@ export const helpRole = (
|
|||||||
.catch(reportRejection)
|
.catch(reportRejection)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: 'Check for updates',
|
||||||
|
click: () => {
|
||||||
|
getAutoUpdater().checkForUpdates().catch(reportRejection)
|
||||||
|
},
|
||||||
|
},
|
||||||
{ type: 'separator' },
|
{ type: 'separator' },
|
||||||
{
|
{
|
||||||
label: 'Manage account',
|
label: 'Manage account',
|
||||||
|
@ -47,6 +47,7 @@ type HelpRoleLabel =
|
|||||||
| 'KCL docs'
|
| 'KCL docs'
|
||||||
| 'Replay onboarding tutorial'
|
| 'Replay onboarding tutorial'
|
||||||
| 'Show release notes'
|
| 'Show release notes'
|
||||||
|
| 'Check for updates'
|
||||||
| 'Manage account'
|
| 'Manage account'
|
||||||
| 'Get started with Text-to-CAD'
|
| 'Get started with Text-to-CAD'
|
||||||
| 'Show all commands'
|
| 'Show all commands'
|
||||||
|
@ -45,6 +45,10 @@ const onUpdateDownloadStart = (
|
|||||||
ipcRenderer.on('update-download-start', (_event: any, value) =>
|
ipcRenderer.on('update-download-start', (_event: any, value) =>
|
||||||
callback(value)
|
callback(value)
|
||||||
)
|
)
|
||||||
|
const onUpdateChecking = (callback: () => void) =>
|
||||||
|
ipcRenderer.on('update-checking', (_event: any) => callback())
|
||||||
|
const onUpdateNotAvailable = (callback: () => void) =>
|
||||||
|
ipcRenderer.on('update-not-available', (_event: any) => callback())
|
||||||
const onUpdateError = (callback: (value: Error) => void) =>
|
const onUpdateError = (callback: (value: Error) => void) =>
|
||||||
ipcRenderer.on('update-error', (_event: any, value) => callback(value))
|
ipcRenderer.on('update-error', (_event: any, value) => callback(value))
|
||||||
const appRestart = () => ipcRenderer.invoke('app.restart')
|
const appRestart = () => ipcRenderer.invoke('app.restart')
|
||||||
@ -305,6 +309,8 @@ contextBridge.exposeInMainWorld('electron', {
|
|||||||
kittycad,
|
kittycad,
|
||||||
listMachines,
|
listMachines,
|
||||||
getMachineApiIp,
|
getMachineApiIp,
|
||||||
|
onUpdateChecking,
|
||||||
|
onUpdateNotAvailable,
|
||||||
onUpdateDownloadStart,
|
onUpdateDownloadStart,
|
||||||
onUpdateDownloaded,
|
onUpdateDownloaded,
|
||||||
onUpdateError,
|
onUpdateError,
|
||||||
|
11
src/updater.ts
Normal file
11
src/updater.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import electronUpdater, { type AppUpdater } from 'electron-updater'
|
||||||
|
|
||||||
|
export function getAutoUpdater(): AppUpdater {
|
||||||
|
// Using destructuring to access autoUpdater due to the CommonJS module of 'electron-updater'.
|
||||||
|
// It is a workaround for ESM compatibility issues, see https://github.com/electron-userland/electron-builder/issues/7976.
|
||||||
|
const { autoUpdater } = electronUpdater
|
||||||
|
// Allows us to rollback to a previous version if needed.
|
||||||
|
// See https://github.com/electron-userland/electron-builder/blob/7dbc6c77c340c869d1e7effa22135fc740003a0f/packages/electron-updater/src/AppUpdater.ts#L450-L451
|
||||||
|
autoUpdater.allowDowngrade = true
|
||||||
|
return autoUpdater
|
||||||
|
}
|
Reference in New Issue
Block a user