Skip to content

Commit a43b850

Browse files
feat(updates): add automatic updates via electron-updater (#822)
* feat(updates): add auto-update via electron-updater * polish(updates): use vertical layout for what's new toast * polish(updates): replace hardcoded what's new toast with generic version-change toast
1 parent db29ea5 commit a43b850

19 files changed

Lines changed: 313 additions & 116 deletions

File tree

electron-builder.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,13 @@
1111
"build/shared/**/*",
1212
"!build/**/*.map"
1313
],
14+
"publish": {
15+
"provider": "github",
16+
"owner": "massCodeIO",
17+
"repo": "massCode"
18+
},
1419
"mac": {
15-
"target": "dmg",
20+
"target": ["dmg", "zip"],
1621
"icon": "build/icons/icon.icns",
1722
"entitlements": "build/entitlements.mac.inherit.plist",
1823
"category": "public.app-category.productivity",

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@
9494
"date-fns": "^4.1.0",
9595
"dom-to-image": "^2.6.0",
9696
"electron-store": "^8.2.0",
97+
"electron-updater": "^6.8.9",
9798
"elysia": "^1.4.16",
9899
"fs-extra": "^11.3.0",
99100
"i18next": "^24.2.2",

pnpm-lock.yaml

Lines changed: 54 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/main/i18n/locales/en_US/messages.json

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,13 @@
9898
"release": {},
9999
"update": {
100100
"available": "Version {{newVersion}} is now available for download.\nYour version is {{oldVersion}}.",
101-
"noAvailable": "There are currently no updates available."
101+
"noAvailable": "There are currently no updates available.",
102+
"downloading": "Update v{{version}} is downloading in the background. You will be prompted to restart when it is ready.",
103+
"availableToast": "Update available",
104+
"goToGitHub": "Go to GitHub",
105+
"downloaded": "Update v{{version}} is ready. Restart massCode to apply it.",
106+
"restart": "Restart",
107+
"whatsNewToast": "See what's new in massCode v{{version}}",
108+
"releaseNotes": "Release notes"
102109
}
103110
}

src/main/i18n/locales/en_US/preferences.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,5 +209,15 @@
209209
"action": "Request a key",
210210
"description": "If you have ever donated to massCode through any channel, send any proof of donation by email and you will receive a key."
211211
}
212+
},
213+
"updates": {
214+
"label": "Updates",
215+
"autoUpdate": {
216+
"label": "Automatic updates",
217+
"description": "Download updates in the background and install them on restart. When disabled, massCode only notifies you about new versions. Major versions are never installed automatically."
218+
},
219+
"version": {
220+
"label": "Current version"
221+
}
212222
}
213223
}

src/main/i18n/locales/ru_RU/messages.json

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,13 @@
9393
"release": {},
9494
"update": {
9595
"available": "Версия {{newVersion}} доступна для загрузки.\nВаша версия {{oldVersion}}.",
96-
"noAvailable": "В настоящее время обновления недоступны."
96+
"noAvailable": "В настоящее время обновления недоступны.",
97+
"downloading": "Обновление v{{version}} скачивается в фоне. Когда оно будет готово, появится предложение перезапустить приложение.",
98+
"availableToast": "Доступно обновление",
99+
"goToGitHub": "Открыть GitHub",
100+
"downloaded": "Обновление v{{version}} готово. Перезапустите massCode, чтобы применить его.",
101+
"restart": "Перезапустить",
102+
"whatsNewToast": "Узнайте, что нового в massCode v{{version}}",
103+
"releaseNotes": "Release notes"
97104
}
98105
}

src/main/i18n/locales/ru_RU/preferences.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,5 +176,15 @@
176176
"action": "Запросить ключ",
177177
"description": "Если вы когда-либо донатили massCode любым способом, отправьте любое подтверждение доната по почте и получите ключ."
178178
}
179+
},
180+
"updates": {
181+
"label": "Обновления",
182+
"autoUpdate": {
183+
"label": "Автоматические обновления",
184+
"description": "Скачивать обновления в фоне и устанавливать при перезапуске. Если выключено, massCode только уведомляет о новых версиях. Новые мажорные версии никогда не устанавливаются автоматически."
185+
},
186+
"version": {
187+
"label": "Текущая версия"
188+
}
179189
}
180190
}

src/main/ipc/handlers/system.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,18 @@ import {
3131
} from '../../storage/providers/markdown/runtime/moveVault'
3232
import { getVaultPath } from '../../storage/providers/markdown/runtime/paths'
3333
import { store } from '../../store'
34+
import { installDownloadedUpdate } from '../../updates'
3435

3536
export function registerSystemHandlers() {
3637
ipcMain.handle('system:activate-license', (_, payload: { key: string }) => {
3738
return activateLicense(payload.key)
3839
})
3940

41+
ipcMain.handle('system:install-update', () => {
42+
installDownloadedUpdate()
43+
return true
44+
})
45+
4046
ipcMain.handle('system:api-token-generate', () => {
4147
return generateIntegrationToken()
4248
})

src/main/menu/main.ts

Lines changed: 2 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,9 @@ import {
1414
type MenuItemConstructorOptions,
1515
shell,
1616
} from 'electron'
17-
import { repository } from '../../../package.json'
1817
import i18n from '../i18n'
1918
import { send } from '../ipc'
20-
import { fetchUpdates } from '../updates'
19+
import { checkForUpdatesFromMenu } from '../updates'
2120
import { createMenu, createPlatformMenuItems } from './utils'
2221

2322
const year = new Date().getFullYear()
@@ -84,33 +83,7 @@ const appMenuItems: MenuConfig[] = [
8483
{
8584
id: 'update',
8685
label: i18n.t('menu:app.update'),
87-
click: async () => {
88-
const latestVersion = await fetchUpdates()
89-
90-
if (latestVersion) {
91-
const buttonId = dialog.showMessageBoxSync(
92-
BrowserWindow.getFocusedWindow()!,
93-
{
94-
message: i18n.t('messages:update.available', {
95-
newVersion: latestVersion,
96-
oldVersion: version,
97-
}),
98-
buttons: [i18n.t('button.update.0'), i18n.t('button.update.1')],
99-
defaultId: 0,
100-
cancelId: 1,
101-
},
102-
)
103-
104-
if (buttonId === 0) {
105-
shell.openExternal(`${repository}/releases`)
106-
}
107-
}
108-
else {
109-
dialog.showMessageBoxSync(BrowserWindow.getFocusedWindow()!, {
110-
message: i18n.t('messages:update.noAvailable'),
111-
})
112-
}
113-
},
86+
click: () => checkForUpdatesFromMenu(),
11487
},
11588
{
11689
type: 'separator',

src/main/store/module/app.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ const APP_STORE_DEFAULTS: AppStore = {
6868
},
6969
notifications: {
7070
lastNotifiedUpdateVersion: '',
71+
lastWhatsNewVersion: '',
7172
},
7273
license: {
7374
key: null,
@@ -648,6 +649,10 @@ function sanitizeAppStore(value: unknown): AppStore {
648649
: typeof source.lastNotifiedUpdateVersion === 'string'
649650
? source.lastNotifiedUpdateVersion
650651
: APP_STORE_DEFAULTS.notifications.lastNotifiedUpdateVersion,
652+
lastWhatsNewVersion:
653+
typeof notificationsSource.lastWhatsNewVersion === 'string'
654+
? notificationsSource.lastWhatsNewVersion
655+
: APP_STORE_DEFAULTS.notifications.lastWhatsNewVersion,
651656
},
652657
license: (() => {
653658
const licenseSource = asRecord(source.license)

0 commit comments

Comments
 (0)