You've already forked joplin
							
							
				mirror of
				https://github.com/laurent22/joplin.git
				synced 2025-10-31 00:07:48 +02:00 
			
		
		
		
	Desktop: Added button to skip an application update
And made auto-updates enabled by default
This commit is contained in:
		| @@ -200,6 +200,9 @@ packages/app-desktop/app.js.map | ||||
| packages/app-desktop/bridge.d.ts | ||||
| packages/app-desktop/bridge.js | ||||
| packages/app-desktop/bridge.js.map | ||||
| packages/app-desktop/checkForUpdates.d.ts | ||||
| packages/app-desktop/checkForUpdates.js | ||||
| packages/app-desktop/checkForUpdates.js.map | ||||
| packages/app-desktop/commands/copyDevCommand.d.ts | ||||
| packages/app-desktop/commands/copyDevCommand.js | ||||
| packages/app-desktop/commands/copyDevCommand.js.map | ||||
|   | ||||
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -186,6 +186,9 @@ packages/app-desktop/app.js.map | ||||
| packages/app-desktop/bridge.d.ts | ||||
| packages/app-desktop/bridge.js | ||||
| packages/app-desktop/bridge.js.map | ||||
| packages/app-desktop/checkForUpdates.d.ts | ||||
| packages/app-desktop/checkForUpdates.js | ||||
| packages/app-desktop/checkForUpdates.js.map | ||||
| packages/app-desktop/commands/copyDevCommand.d.ts | ||||
| packages/app-desktop/commands/copyDevCommand.js | ||||
| packages/app-desktop/commands/copyDevCommand.js.map | ||||
|   | ||||
| @@ -103,6 +103,7 @@ const globalCommands = [ | ||||
|  | ||||
| import editorCommandDeclarations from './gui/NoteEditor/commands/editorCommandDeclarations'; | ||||
| import ShareService from '@joplin/lib/services/share/ShareService'; | ||||
| import checkForUpdates from './checkForUpdates'; | ||||
|  | ||||
| const pluginClasses = [ | ||||
| 	require('./plugins/GotoAnything').default, | ||||
| @@ -167,10 +168,6 @@ class Application extends BaseApplication { | ||||
| 		return true; | ||||
| 	} | ||||
|  | ||||
| 	checkForUpdateLoggerPath() { | ||||
| 		return `${Setting.value('profileDir')}/log-autoupdater.txt`; | ||||
| 	} | ||||
|  | ||||
| 	reducer(state: AppState = appDefaultState, action: any) { | ||||
| 		let newState = state; | ||||
|  | ||||
| @@ -711,7 +708,7 @@ class Application extends BaseApplication { | ||||
| 		if (shim.isWindows() || shim.isMac()) { | ||||
| 			const runAutoUpdateCheck = () => { | ||||
| 				if (Setting.value('autoUpdateEnabled')) { | ||||
| 					bridge().checkForUpdates(true, bridge().window(), this.checkForUpdateLoggerPath(), { includePreReleases: Setting.value('autoUpdate.includePreReleases') }); | ||||
| 					void checkForUpdates(true, bridge().window(), { includePreReleases: Setting.value('autoUpdate.includePreReleases') }); | ||||
| 				} | ||||
| 			}; | ||||
|  | ||||
|   | ||||
| @@ -1,6 +1,5 @@ | ||||
| import ElectronAppWrapper from './ElectronAppWrapper'; | ||||
| import shim from '@joplin/lib/shim'; | ||||
|  | ||||
| import { _, setLocale } from '@joplin/lib/locale'; | ||||
| const { dirname, toSystemSlashes } = require('@joplin/lib/path-utils'); | ||||
| const { BrowserWindow, nativeTheme } = require('electron'); | ||||
| @@ -174,11 +173,6 @@ export class Bridge { | ||||
| 		return require('electron').shell.openPath(fullPath); | ||||
| 	} | ||||
|  | ||||
| 	checkForUpdates(inBackground: boolean, window: any, logFilePath: string, options: any) { | ||||
| 		const { checkForUpdates } = require('./checkForUpdates.js'); | ||||
| 		checkForUpdates(inBackground, window, logFilePath, options); | ||||
| 	} | ||||
|  | ||||
| 	buildDir() { | ||||
| 		return this.electronApp().buildDir(); | ||||
| 	} | ||||
|   | ||||
| @@ -1,44 +1,42 @@ | ||||
| const { dialog } = require('electron'); | ||||
| const shim = require('@joplin/lib/shim').default; | ||||
| const Logger = require('@joplin/lib/Logger').default; | ||||
| const { _ } = require('@joplin/lib/locale'); | ||||
| const fetch = require('node-fetch'); | ||||
| import shim from '@joplin/lib/shim'; | ||||
| import Logger from '@joplin/lib/Logger'; | ||||
| import { _ } from '@joplin/lib/locale'; | ||||
| import bridge from './services/bridge'; | ||||
| import KvStore from '@joplin/lib/services/KvStore'; | ||||
| const { fileExtension } = require('@joplin/lib/path-utils'); | ||||
| const ArrayUtils = require('@joplin/lib/ArrayUtils'); | ||||
| const packageInfo = require('./packageInfo.js'); | ||||
| const compareVersions = require('compare-versions'); | ||||
| 
 | ||||
| let autoUpdateLogger_ = new Logger(); | ||||
| const logger = Logger.create('checkForUpdates'); | ||||
| 
 | ||||
| let checkInBackground_ = false; | ||||
| let isCheckingForUpdate_ = false; | ||||
| let parentWindow_ = null; | ||||
| 
 | ||||
| function showErrorMessageBox(message) { | ||||
| 	return dialog.showMessageBox(parentWindow_, { | ||||
| 		type: 'error', | ||||
| 		message: message, | ||||
| 	}); | ||||
| interface CheckForUpdateOptions { | ||||
| 	includePreReleases?: boolean; | ||||
| } | ||||
| 
 | ||||
| function onCheckStarted() { | ||||
| 	autoUpdateLogger_.info('checkForUpdates: Starting...'); | ||||
| 	logger.info('Starting...'); | ||||
| 	isCheckingForUpdate_ = true; | ||||
| } | ||||
| 
 | ||||
| function onCheckEnded() { | ||||
| 	autoUpdateLogger_.info('checkForUpdates: Done.'); | ||||
| 	logger.info('Done.'); | ||||
| 	isCheckingForUpdate_ = false; | ||||
| } | ||||
| 
 | ||||
| function getMajorMinorTagName(tagName) { | ||||
| function getMajorMinorTagName(tagName: string) { | ||||
| 	const s = tagName.split('.'); | ||||
| 	s.pop(); | ||||
| 	return s.join('.'); | ||||
| } | ||||
| 
 | ||||
| async function fetchLatestRelease(options) { | ||||
| async function fetchLatestRelease(options: CheckForUpdateOptions) { | ||||
| 	options = Object.assign({}, { includePreReleases: false }, options); | ||||
| 
 | ||||
| 	const response = await fetch('https://api.github.com/repos/laurent22/joplin/releases'); | ||||
| 	const response = await shim.fetch('https://api.github.com/repos/laurent22/joplin/releases'); | ||||
| 
 | ||||
| 	if (!response.ok) { | ||||
| 		const responseText = await response.text(); | ||||
| @@ -104,7 +102,7 @@ async function fetchLatestRelease(options) { | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	function cleanUpReleaseNotes(releaseNotes) { | ||||
| 	function cleanUpReleaseNotes(releaseNotes: string[]) { | ||||
| 		const lines = releaseNotes.join('\n\n* * *\n\n').split('\n'); | ||||
| 		const output = []; | ||||
| 		for (const line of lines) { | ||||
| @@ -129,7 +127,7 @@ async function fetchLatestRelease(options) { | ||||
| 	}; | ||||
| } | ||||
| 
 | ||||
| function truncateText(text, length) { | ||||
| function truncateText(text: string, length: number) { | ||||
| 	let truncated = text.substring(0, length); | ||||
| 	const lastNewLine = truncated.lastIndexOf('\n'); | ||||
| 	// Cut off at a line break unless we'd be cutting off half the text
 | ||||
| @@ -141,66 +139,80 @@ function truncateText(text, length) { | ||||
| 	return truncated; | ||||
| } | ||||
| 
 | ||||
| function checkForUpdates(inBackground, window, logFilePath, options) { | ||||
| async function getSkippedVersions(): Promise<string[]> { | ||||
| 	const r = await KvStore.instance().value<string>('updateCheck::skippedVersions'); | ||||
| 	return r ? JSON.parse(r) : []; | ||||
| } | ||||
| 
 | ||||
| async function isSkippedVersion(v: string): Promise<boolean> { | ||||
| 	const versions = await getSkippedVersions(); | ||||
| 	return versions.includes(v); | ||||
| } | ||||
| 
 | ||||
| async function addSkippedVersion(s: string) { | ||||
| 	let versions = await getSkippedVersions(); | ||||
| 	versions.push(s); | ||||
| 	versions = ArrayUtils.unique(versions); | ||||
| 	await KvStore.instance().setValue('updateCheck::skippedVersions', JSON.stringify(versions)); | ||||
| } | ||||
| 
 | ||||
| export default async function checkForUpdates(inBackground: boolean, parentWindow: any, options: CheckForUpdateOptions) { | ||||
| 	if (isCheckingForUpdate_) { | ||||
| 		autoUpdateLogger_.info('checkForUpdates: Skipping check because it is already running'); | ||||
| 		logger.info('Skipping check because it is already running'); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	parentWindow_ = window; | ||||
| 
 | ||||
| 	onCheckStarted(); | ||||
| 
 | ||||
| 	if (logFilePath && !autoUpdateLogger_.targets().length) { | ||||
| 		autoUpdateLogger_ = new Logger(); | ||||
| 		autoUpdateLogger_.addTarget('file', { path: logFilePath }); | ||||
| 		autoUpdateLogger_.setLevel(Logger.LEVEL_DEBUG); | ||||
| 		autoUpdateLogger_.info('checkForUpdates: Initializing...'); | ||||
| 	} | ||||
| 
 | ||||
| 	checkInBackground_ = inBackground; | ||||
| 
 | ||||
| 	autoUpdateLogger_.info(`checkForUpdates: Checking with options ${JSON.stringify(options)}`); | ||||
| 	logger.info(`Checking with options ${JSON.stringify(options)}`); | ||||
| 
 | ||||
| 	fetchLatestRelease(options).then(async (release) => { | ||||
| 		autoUpdateLogger_.info(`Current version: ${packageInfo.version}`); | ||||
| 		autoUpdateLogger_.info(`Latest version: ${release.version}`); | ||||
| 		autoUpdateLogger_.info('Is Pre-release:', release.prerelease); | ||||
| 	try { | ||||
| 		const release = await fetchLatestRelease(options); | ||||
| 
 | ||||
| 		logger.info(`Current version: ${packageInfo.version}`); | ||||
| 		logger.info(`Latest version: ${release.version}`); | ||||
| 		logger.info('Is Pre-release:', release.prerelease); | ||||
| 
 | ||||
| 		if (compareVersions(release.version, packageInfo.version) <= 0) { | ||||
| 			if (!checkInBackground_) { | ||||
| 				await dialog.showMessageBox({ | ||||
| 					type: 'info', | ||||
| 					message: _('Current version is up-to-date.'), | ||||
| 					buttons: [_('OK')], | ||||
| 				}); | ||||
| 				await bridge().showMessageBox(_('Current version is up-to-date.')); | ||||
| 			} | ||||
| 		} else { | ||||
| 			const fullReleaseNotes = release.notes.trim() ? `\n\n${release.notes.trim()}` : ''; | ||||
| 			const MAX_RELEASE_NOTES_LENGTH = 1000; | ||||
| 			const truncateReleaseNotes = fullReleaseNotes.length > MAX_RELEASE_NOTES_LENGTH; | ||||
| 			const releaseNotes = truncateReleaseNotes ? truncateText(fullReleaseNotes, MAX_RELEASE_NOTES_LENGTH) : fullReleaseNotes; | ||||
| 			const shouldSkip = checkInBackground_ && await isSkippedVersion(release.version); | ||||
| 
 | ||||
| 			const newVersionString = release.prerelease ? _('%s (pre-release)', release.version) : release.version; | ||||
| 			if (shouldSkip) { | ||||
| 				logger.info('Not displaying notification because version has been skipped'); | ||||
| 			} else { | ||||
| 				const fullReleaseNotes = release.notes.trim() ? `\n\n${release.notes.trim()}` : ''; | ||||
| 				const MAX_RELEASE_NOTES_LENGTH = 1000; | ||||
| 				const truncateReleaseNotes = fullReleaseNotes.length > MAX_RELEASE_NOTES_LENGTH; | ||||
| 				const releaseNotes = truncateReleaseNotes ? truncateText(fullReleaseNotes, MAX_RELEASE_NOTES_LENGTH) : fullReleaseNotes; | ||||
| 
 | ||||
| 			const result = await dialog.showMessageBox(parentWindow_, { | ||||
| 				type: 'info', | ||||
| 				message: `${_('An update is available, do you want to download it now?')}`, | ||||
| 				detail: `${_('Your version: %s', packageInfo.version)}\n${_('New version: %s', newVersionString)}${releaseNotes}`, | ||||
| 				buttons: [_('Download'), _('Cancel'), _('Full changelog')], | ||||
| 				cancelId: 1, | ||||
| 			}); | ||||
| 				const newVersionString = release.prerelease ? _('%s (pre-release)', release.version) : release.version; | ||||
| 
 | ||||
| 			const buttonIndex = result.response; | ||||
| 			if (buttonIndex === 0) require('electron').shell.openExternal(release.downloadUrl ? release.downloadUrl : release.pageUrl); | ||||
| 			if (buttonIndex === 2) require('electron').shell.openExternal('https://joplinapp.org/changelog/'); | ||||
| 				const buttonIndex = await bridge().showMessageBox(parentWindow, { | ||||
| 					type: 'info', | ||||
| 					message: `${_('An update is available, do you want to download it now?')}`, | ||||
| 					detail: `${_('Your version: %s', packageInfo.version)}\n${_('New version: %s', newVersionString)}${releaseNotes}`, | ||||
| 					buttons: [_('Download'), _('Skip this version'), _('Full changelog'), _('Cancel')], | ||||
| 					cancelId: 3, | ||||
| 				}); | ||||
| 
 | ||||
| 				if (buttonIndex === 0) { | ||||
| 					bridge().openExternal(release.downloadUrl ? release.downloadUrl : release.pageUrl); | ||||
| 				} else if (buttonIndex === 1) { | ||||
| 					await addSkippedVersion(release.version); | ||||
| 				} else if (buttonIndex === 2) { | ||||
| 					bridge().openExternal('https://joplinapp.org/changelog/'); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	}).catch(error => { | ||||
| 		autoUpdateLogger_.error(error); | ||||
| 		if (!checkInBackground_) showErrorMessageBox(error.message); | ||||
| 	}).then(() => { | ||||
| 	} catch (error) { | ||||
| 		logger.error(error); | ||||
| 		if (!checkInBackground_) await bridge().showErrorMessageBox(error.message); | ||||
| 	} finally { | ||||
| 		onCheckEnded(); | ||||
| 	}); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| module.exports.checkForUpdates = checkForUpdates; | ||||
| @@ -17,6 +17,7 @@ import SpellCheckerService from '@joplin/lib/services/spellChecker/SpellCheckerS | ||||
| import menuCommandNames from './menuCommandNames'; | ||||
| import stateToWhenClauseContext from '../services/commands/stateToWhenClauseContext'; | ||||
| import bridge from '../services/bridge'; | ||||
| import checkForUpdates from '../checkForUpdates'; | ||||
|  | ||||
| const { connect } = require('react-redux'); | ||||
| import { reg } from '@joplin/lib/registry'; | ||||
| @@ -430,7 +431,7 @@ function useMenu(props: Props) { | ||||
| 			toolsItems.push(SpellCheckerService.instance().spellCheckerConfigMenuItem(props['spellChecker.language'], props['spellChecker.enabled'])); | ||||
|  | ||||
| 			function _checkForUpdates() { | ||||
| 				bridge().checkForUpdates(false, bridge().window(), `${Setting.value('profileDir')}/log-autoupdater.txt`, { includePreReleases: Setting.value('autoUpdate.includePreReleases') }); | ||||
| 				void checkForUpdates(false, bridge().window(), { includePreReleases: Setting.value('autoUpdate.includePreReleases') }); | ||||
| 			} | ||||
|  | ||||
| 			function _showAbout() { | ||||
|   | ||||
| @@ -992,7 +992,7 @@ class Setting extends BaseModel { | ||||
| 			}, | ||||
|  | ||||
|  | ||||
| 			autoUpdateEnabled: { value: false, type: SettingItemType.Bool, storage: SettingStorage.File, section: 'application', public: platform !== 'linux', appTypes: ['desktop'], label: () => _('Automatically update the application') }, | ||||
| 			autoUpdateEnabled: { value: true, type: SettingItemType.Bool, storage: SettingStorage.File, section: 'application', public: platform !== 'linux', appTypes: ['desktop'], label: () => _('Automatically update the application') }, | ||||
| 			'autoUpdate.includePreReleases': { value: false, type: SettingItemType.Bool, section: 'application', storage: SettingStorage.File, public: true, appTypes: ['desktop'], label: () => _('Get pre-releases when checking for updates'), description: () => _('See the pre-release page for more details: %s', 'https://joplinapp.org/prereleases') }, | ||||
| 			'clipperServer.autoStart': { value: false, type: SettingItemType.Bool, storage: SettingStorage.File, public: false }, | ||||
| 			'sync.interval': { | ||||
|   | ||||
| @@ -169,7 +169,7 @@ const shim = { | ||||
| 		} | ||||
| 	}, | ||||
|  | ||||
| 	fetch: (_url: string, _options: any): any => { | ||||
| 	fetch: (_url: string, _options: any = null): any => { | ||||
| 		throw new Error('Not implemented'); | ||||
| 	}, | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user