mirror of
https://github.com/laurent22/joplin.git
synced 2024-12-21 09:38:01 +02:00
Desktop: Ask to start in safe mode when the application has crashed
This commit is contained in:
parent
bd917ae09c
commit
d9a4a9cb30
@ -808,6 +808,9 @@ packages/app-desktop/services/plugins/hooks/useViewIsReady.js.map
|
|||||||
packages/app-desktop/services/plugins/hooks/useWebviewToPluginMessages.d.ts
|
packages/app-desktop/services/plugins/hooks/useWebviewToPluginMessages.d.ts
|
||||||
packages/app-desktop/services/plugins/hooks/useWebviewToPluginMessages.js
|
packages/app-desktop/services/plugins/hooks/useWebviewToPluginMessages.js
|
||||||
packages/app-desktop/services/plugins/hooks/useWebviewToPluginMessages.js.map
|
packages/app-desktop/services/plugins/hooks/useWebviewToPluginMessages.js.map
|
||||||
|
packages/app-desktop/services/restart.d.ts
|
||||||
|
packages/app-desktop/services/restart.js
|
||||||
|
packages/app-desktop/services/restart.js.map
|
||||||
packages/app-desktop/services/share/invitationRespond.d.ts
|
packages/app-desktop/services/share/invitationRespond.d.ts
|
||||||
packages/app-desktop/services/share/invitationRespond.js
|
packages/app-desktop/services/share/invitationRespond.js
|
||||||
packages/app-desktop/services/share/invitationRespond.js.map
|
packages/app-desktop/services/share/invitationRespond.js.map
|
||||||
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -798,6 +798,9 @@ packages/app-desktop/services/plugins/hooks/useViewIsReady.js.map
|
|||||||
packages/app-desktop/services/plugins/hooks/useWebviewToPluginMessages.d.ts
|
packages/app-desktop/services/plugins/hooks/useWebviewToPluginMessages.d.ts
|
||||||
packages/app-desktop/services/plugins/hooks/useWebviewToPluginMessages.js
|
packages/app-desktop/services/plugins/hooks/useWebviewToPluginMessages.js
|
||||||
packages/app-desktop/services/plugins/hooks/useWebviewToPluginMessages.js.map
|
packages/app-desktop/services/plugins/hooks/useWebviewToPluginMessages.js.map
|
||||||
|
packages/app-desktop/services/restart.d.ts
|
||||||
|
packages/app-desktop/services/restart.js
|
||||||
|
packages/app-desktop/services/restart.js.map
|
||||||
packages/app-desktop/services/share/invitationRespond.d.ts
|
packages/app-desktop/services/share/invitationRespond.d.ts
|
||||||
packages/app-desktop/services/share/invitationRespond.js
|
packages/app-desktop/services/share/invitationRespond.js
|
||||||
packages/app-desktop/services/share/invitationRespond.js.map
|
packages/app-desktop/services/share/invitationRespond.js.map
|
||||||
|
@ -192,7 +192,7 @@ export default class ElectronAppWrapper {
|
|||||||
// We got the response from the renderer process:
|
// We got the response from the renderer process:
|
||||||
// save the response and try quit again.
|
// save the response and try quit again.
|
||||||
this.rendererProcessQuitReply_ = args;
|
this.rendererProcessQuitReply_ = args;
|
||||||
this.electronApp_.quit();
|
this.quit();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -253,7 +253,7 @@ export default class ElectronAppWrapper {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async quit() {
|
quit() {
|
||||||
this.electronApp_.quit();
|
this.electronApp_.quit();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -325,7 +325,7 @@ export default class ElectronAppWrapper {
|
|||||||
|
|
||||||
if (!gotTheLock) {
|
if (!gotTheLock) {
|
||||||
// Another instance is already running - exit
|
// Another instance is already running - exit
|
||||||
this.electronApp_.quit();
|
this.quit();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -362,7 +362,7 @@ export default class ElectronAppWrapper {
|
|||||||
});
|
});
|
||||||
|
|
||||||
this.electronApp_.on('window-all-closed', () => {
|
this.electronApp_.on('window-all-closed', () => {
|
||||||
this.electronApp_.quit();
|
this.quit();
|
||||||
});
|
});
|
||||||
|
|
||||||
this.electronApp_.on('activate', () => {
|
this.electronApp_.on('activate', () => {
|
||||||
|
@ -324,6 +324,15 @@ class Application extends BaseApplication {
|
|||||||
}, 500);
|
}, 500);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private crashDetectionHandler() {
|
||||||
|
if (!Setting.value('wasClosedSuccessfully')) {
|
||||||
|
const answer = confirm(_('The application did not close properly. Would you like to start in safe mode?'));
|
||||||
|
Setting.setValue('isSafeMode', !!answer);
|
||||||
|
}
|
||||||
|
|
||||||
|
Setting.setValue('wasClosedSuccessfully', false);
|
||||||
|
}
|
||||||
|
|
||||||
public async start(argv: string[]): Promise<any> {
|
public async start(argv: string[]): Promise<any> {
|
||||||
// If running inside a package, the command line, instead of being "node.exe <path> <flags>" is "joplin.exe <flags>" so
|
// If running inside a package, the command line, instead of being "node.exe <path> <flags>" is "joplin.exe <flags>" so
|
||||||
// insert an extra argument so that they can be processed in a consistent way everywhere.
|
// insert an extra argument so that they can be processed in a consistent way everywhere.
|
||||||
@ -331,6 +340,8 @@ class Application extends BaseApplication {
|
|||||||
|
|
||||||
argv = await super.start(argv);
|
argv = await super.start(argv);
|
||||||
|
|
||||||
|
this.crashDetectionHandler();
|
||||||
|
|
||||||
await this.applySettingsSideEffects();
|
await this.applySettingsSideEffects();
|
||||||
|
|
||||||
if (Setting.value('sync.upgradeState') === Setting.SYNC_UPGRADE_STATE_MUST_DO) {
|
if (Setting.value('sync.upgradeState') === Setting.SYNC_UPGRADE_STATE_MUST_DO) {
|
||||||
|
@ -2,7 +2,7 @@ import { CommandRuntime, CommandDeclaration, CommandContext } from '@joplin/lib/
|
|||||||
import Setting from '@joplin/lib/models/Setting';
|
import Setting from '@joplin/lib/models/Setting';
|
||||||
import { saveProfileConfig } from '@joplin/lib/services/profileConfig';
|
import { saveProfileConfig } from '@joplin/lib/services/profileConfig';
|
||||||
import { ProfileConfig } from '@joplin/lib/services/profileConfig/types';
|
import { ProfileConfig } from '@joplin/lib/services/profileConfig/types';
|
||||||
import bridge from '../services/bridge';
|
import restart from '../services/restart';
|
||||||
|
|
||||||
export const declaration: CommandDeclaration = {
|
export const declaration: CommandDeclaration = {
|
||||||
name: 'switchProfile',
|
name: 'switchProfile',
|
||||||
@ -20,7 +20,7 @@ export const runtime = (): CommandRuntime => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
await saveProfileConfig(`${Setting.value('rootProfileDir')}/profiles.json`, newConfig);
|
await saveProfileConfig(`${Setting.value('rootProfileDir')}/profiles.json`, newConfig);
|
||||||
bridge().restart(false);
|
await restart(false);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { _ } from '@joplin/lib/locale';
|
import { _ } from '@joplin/lib/locale';
|
||||||
import Setting from '@joplin/lib/models/Setting';
|
import Setting from '@joplin/lib/models/Setting';
|
||||||
import { CommandRuntime, CommandDeclaration, CommandContext } from '@joplin/lib/services/CommandService';
|
import { CommandRuntime, CommandDeclaration, CommandContext } from '@joplin/lib/services/CommandService';
|
||||||
import bridge from '../services/bridge';
|
import restart from '../services/restart';
|
||||||
|
|
||||||
export const declaration: CommandDeclaration = {
|
export const declaration: CommandDeclaration = {
|
||||||
name: 'toggleSafeMode',
|
name: 'toggleSafeMode',
|
||||||
@ -14,7 +14,7 @@ export const runtime = (): CommandRuntime => {
|
|||||||
enabled = enabled !== null ? enabled : !Setting.value('isSafeMode');
|
enabled = enabled !== null ? enabled : !Setting.value('isSafeMode');
|
||||||
Setting.setValue('isSafeMode', enabled);
|
Setting.setValue('isSafeMode', enabled);
|
||||||
await Setting.saveAll();
|
await Setting.saveAll();
|
||||||
bridge().restart();
|
await restart();
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -14,6 +14,7 @@ const pathUtils = require('@joplin/lib/path-utils');
|
|||||||
import SyncTargetRegistry from '@joplin/lib/SyncTargetRegistry';
|
import SyncTargetRegistry from '@joplin/lib/SyncTargetRegistry';
|
||||||
const shared = require('@joplin/lib/components/shared/config-shared.js');
|
const shared = require('@joplin/lib/components/shared/config-shared.js');
|
||||||
import ClipperConfigScreen from '../ClipperConfigScreen';
|
import ClipperConfigScreen from '../ClipperConfigScreen';
|
||||||
|
import restart from '../../services/restart';
|
||||||
const { KeymapConfigScreen } = require('../KeymapConfig/KeymapConfigScreen');
|
const { KeymapConfigScreen } = require('../KeymapConfig/KeymapConfigScreen');
|
||||||
|
|
||||||
const settingKeyToControl: any = {
|
const settingKeyToControl: any = {
|
||||||
@ -72,12 +73,12 @@ class ConfigScreenComponent extends React.Component<any, any> {
|
|||||||
if (!confirm('This cannot be undone. Do you want to continue?')) return;
|
if (!confirm('This cannot be undone. Do you want to continue?')) return;
|
||||||
Setting.setValue('sync.startupOperation', SyncStartupOperation.ClearLocalSyncState);
|
Setting.setValue('sync.startupOperation', SyncStartupOperation.ClearLocalSyncState);
|
||||||
await Setting.saveAll();
|
await Setting.saveAll();
|
||||||
bridge().restart();
|
await restart();
|
||||||
} else if (key === 'sync.clearLocalDataButton') {
|
} else if (key === 'sync.clearLocalDataButton') {
|
||||||
if (!confirm('This cannot be undone. Do you want to continue?')) return;
|
if (!confirm('This cannot be undone. Do you want to continue?')) return;
|
||||||
Setting.setValue('sync.startupOperation', SyncStartupOperation.ClearLocalData);
|
Setting.setValue('sync.startupOperation', SyncStartupOperation.ClearLocalData);
|
||||||
await Setting.saveAll();
|
await Setting.saveAll();
|
||||||
bridge().restart();
|
await restart();
|
||||||
} else if (key === 'sync.openSyncWizard') {
|
} else if (key === 'sync.openSyncWizard') {
|
||||||
this.props.dispatch({
|
this.props.dispatch({
|
||||||
type: 'DIALOG_OPEN',
|
type: 'DIALOG_OPEN',
|
||||||
@ -632,7 +633,7 @@ class ConfigScreenComponent extends React.Component<any, any> {
|
|||||||
|
|
||||||
private async restartApp() {
|
private async restartApp() {
|
||||||
await Setting.saveAll();
|
await Setting.saveAll();
|
||||||
bridge().restart();
|
await restart();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async checkNeedRestart() {
|
private async checkNeedRestart() {
|
||||||
|
@ -2,7 +2,7 @@ import * as React from 'react';
|
|||||||
import versionInfo from '@joplin/lib/versionInfo';
|
import versionInfo from '@joplin/lib/versionInfo';
|
||||||
import PluginService from '@joplin/lib/services/plugins/PluginService';
|
import PluginService from '@joplin/lib/services/plugins/PluginService';
|
||||||
import Setting from '@joplin/lib/models/Setting';
|
import Setting from '@joplin/lib/models/Setting';
|
||||||
import bridge from '../services/bridge';
|
import restart from '../services/restart';
|
||||||
const packageInfo = require('../packageInfo.js');
|
const packageInfo = require('../packageInfo.js');
|
||||||
const ipcRenderer = require('electron').ipcRenderer;
|
const ipcRenderer = require('electron').ipcRenderer;
|
||||||
|
|
||||||
@ -75,7 +75,7 @@ export default class ErrorBoundary extends React.Component<Props, State> {
|
|||||||
const safeMode_click = async () => {
|
const safeMode_click = async () => {
|
||||||
Setting.setValue('isSafeMode', true);
|
Setting.setValue('isSafeMode', true);
|
||||||
await Setting.saveAll();
|
await Setting.saveAll();
|
||||||
bridge().restart();
|
await restart();
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -40,6 +40,7 @@ import { showMissingMasterKeyMessage } from '@joplin/lib/services/e2ee/utils';
|
|||||||
import { MasterKeyEntity } from '@joplin/lib/services/e2ee/types';
|
import { MasterKeyEntity } from '@joplin/lib/services/e2ee/types';
|
||||||
import commands from './commands/index';
|
import commands from './commands/index';
|
||||||
import invitationRespond from '../../services/share/invitationRespond';
|
import invitationRespond from '../../services/share/invitationRespond';
|
||||||
|
import restart from '../../services/restart';
|
||||||
const { connect } = require('react-redux');
|
const { connect } = require('react-redux');
|
||||||
const { PromptDialog } = require('../PromptDialog.min.js');
|
const { PromptDialog } = require('../PromptDialog.min.js');
|
||||||
const NotePropertiesDialog = require('../NotePropertiesDialog.min.js');
|
const NotePropertiesDialog = require('../NotePropertiesDialog.min.js');
|
||||||
@ -267,18 +268,22 @@ class MainScreenComponent extends React.Component<Props, State> {
|
|||||||
if (this.waitForNotesSavedIID_) shim.clearInterval(this.waitForNotesSavedIID_);
|
if (this.waitForNotesSavedIID_) shim.clearInterval(this.waitForNotesSavedIID_);
|
||||||
this.waitForNotesSavedIID_ = null;
|
this.waitForNotesSavedIID_ = null;
|
||||||
|
|
||||||
ipcRenderer.send('asynchronous-message', 'appCloseReply', {
|
const sendCanClose = async (canClose: boolean) => {
|
||||||
canClose: !this.props.hasNotesBeingSaved,
|
if (canClose) {
|
||||||
});
|
Setting.setValue('wasClosedSuccessfully', true);
|
||||||
|
await Setting.saveAll();
|
||||||
|
}
|
||||||
|
ipcRenderer.send('asynchronous-message', 'appCloseReply', { canClose });
|
||||||
|
};
|
||||||
|
|
||||||
|
await sendCanClose(!this.props.hasNotesBeingSaved);
|
||||||
|
|
||||||
if (this.props.hasNotesBeingSaved) {
|
if (this.props.hasNotesBeingSaved) {
|
||||||
this.waitForNotesSavedIID_ = shim.setInterval(() => {
|
this.waitForNotesSavedIID_ = shim.setInterval(() => {
|
||||||
if (!this.props.hasNotesBeingSaved) {
|
if (!this.props.hasNotesBeingSaved) {
|
||||||
shim.clearInterval(this.waitForNotesSavedIID_);
|
shim.clearInterval(this.waitForNotesSavedIID_);
|
||||||
this.waitForNotesSavedIID_ = null;
|
this.waitForNotesSavedIID_ = null;
|
||||||
ipcRenderer.send('asynchronous-message', 'appCloseReply', {
|
void sendCanClose(true);
|
||||||
canClose: true,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}, 50);
|
}, 50);
|
||||||
}
|
}
|
||||||
@ -557,13 +562,13 @@ class MainScreenComponent extends React.Component<Props, State> {
|
|||||||
const onRestartAndUpgrade = async () => {
|
const onRestartAndUpgrade = async () => {
|
||||||
Setting.setValue('sync.upgradeState', Setting.SYNC_UPGRADE_STATE_MUST_DO);
|
Setting.setValue('sync.upgradeState', Setting.SYNC_UPGRADE_STATE_MUST_DO);
|
||||||
await Setting.saveAll();
|
await Setting.saveAll();
|
||||||
bridge().restart();
|
await restart();
|
||||||
};
|
};
|
||||||
|
|
||||||
const onDisableSafeModeAndRestart = async () => {
|
const onDisableSafeModeAndRestart = async () => {
|
||||||
Setting.setValue('isSafeMode', false);
|
Setting.setValue('isSafeMode', false);
|
||||||
await Setting.saveAll();
|
await Setting.saveAll();
|
||||||
bridge().restart();
|
await restart();
|
||||||
};
|
};
|
||||||
|
|
||||||
const onInvitationRespond = async (shareUserId: string, folderId: string, masterKey: MasterKeyEntity, accept: boolean) => {
|
const onInvitationRespond = async (shareUserId: string, folderId: string, masterKey: MasterKeyEntity, accept: boolean) => {
|
||||||
|
@ -2,7 +2,7 @@ import { CommandRuntime, CommandDeclaration, CommandContext } from '@joplin/lib/
|
|||||||
import { _ } from '@joplin/lib/locale';
|
import { _ } from '@joplin/lib/locale';
|
||||||
import { createNewProfile, saveProfileConfig } from '@joplin/lib/services/profileConfig';
|
import { createNewProfile, saveProfileConfig } from '@joplin/lib/services/profileConfig';
|
||||||
import Setting from '@joplin/lib/models/Setting';
|
import Setting from '@joplin/lib/models/Setting';
|
||||||
import bridge from '../../../services/bridge';
|
import restart from '../../../services/restart';
|
||||||
|
|
||||||
export const declaration: CommandDeclaration = {
|
export const declaration: CommandDeclaration = {
|
||||||
name: 'addProfile',
|
name: 'addProfile',
|
||||||
@ -22,7 +22,7 @@ export const runtime = (comp: any): CommandRuntime => {
|
|||||||
const { newConfig, newProfile } = createNewProfile(context.state.profileConfig, answer);
|
const { newConfig, newProfile } = createNewProfile(context.state.profileConfig, answer);
|
||||||
newConfig.currentProfileId = newProfile.id;
|
newConfig.currentProfileId = newProfile.id;
|
||||||
await saveProfileConfig(`${Setting.value('rootProfileDir')}/profiles.json`, newConfig);
|
await saveProfileConfig(`${Setting.value('rootProfileDir')}/profiles.json`, newConfig);
|
||||||
bridge().restart(false);
|
await restart(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
comp.setState({ promptOptions: null });
|
comp.setState({ promptOptions: null });
|
||||||
|
@ -5,7 +5,7 @@ import useSyncTargetUpgrade, { SyncTargetUpgradeResult } from '@joplin/lib/servi
|
|||||||
const { render } = require('react-dom');
|
const { render } = require('react-dom');
|
||||||
const ipcRenderer = require('electron').ipcRenderer;
|
const ipcRenderer = require('electron').ipcRenderer;
|
||||||
import Setting from '@joplin/lib/models/Setting';
|
import Setting from '@joplin/lib/models/Setting';
|
||||||
const bridge = require('@electron/remote').require('./bridge').default;
|
import restart from '../services/restart';
|
||||||
|
|
||||||
function useAppCloseHandler(upgradeResult: SyncTargetUpgradeResult) {
|
function useAppCloseHandler(upgradeResult: SyncTargetUpgradeResult) {
|
||||||
useEffect(function() {
|
useEffect(function() {
|
||||||
@ -64,7 +64,7 @@ function useStyle() {
|
|||||||
function useRestartOnDone(upgradeResult: SyncTargetUpgradeResult) {
|
function useRestartOnDone(upgradeResult: SyncTargetUpgradeResult) {
|
||||||
useEffect(function() {
|
useEffect(function() {
|
||||||
if (upgradeResult.done && !upgradeResult.error) {
|
if (upgradeResult.done && !upgradeResult.error) {
|
||||||
bridge().restart();
|
void restart();
|
||||||
}
|
}
|
||||||
}, [upgradeResult.done]);
|
}, [upgradeResult.done]);
|
||||||
}
|
}
|
||||||
|
10
packages/app-desktop/services/restart.ts
Normal file
10
packages/app-desktop/services/restart.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import Setting from '@joplin/lib/models/Setting';
|
||||||
|
import bridge from './bridge';
|
||||||
|
|
||||||
|
|
||||||
|
export default async (linuxSafeRestart: boolean = true) => {
|
||||||
|
Setting.setValue('wasClosedSuccessfully', true);
|
||||||
|
await Setting.saveAll();
|
||||||
|
|
||||||
|
bridge().restart(linuxSafeRestart);
|
||||||
|
};
|
@ -1500,6 +1500,12 @@ class Setting extends BaseModel {
|
|||||||
public: false,
|
public: false,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
wasClosedSuccessfully: {
|
||||||
|
value: true,
|
||||||
|
type: SettingItemType.Bool,
|
||||||
|
public: false,
|
||||||
|
},
|
||||||
|
|
||||||
// 'featureFlag.syncAccurateTimestamps': {
|
// 'featureFlag.syncAccurateTimestamps': {
|
||||||
// value: false,
|
// value: false,
|
||||||
// type: SettingItemType.Bool,
|
// type: SettingItemType.Bool,
|
||||||
|
Loading…
Reference in New Issue
Block a user