1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-09-02 20:46:21 +02:00

Compare commits

...

10 Commits

Author SHA1 Message Date
Laurent Cozic
23d492f79e Desktop release v2.10.17 2023-05-08 17:12:29 +01:00
Laurent Cozic
346a9c6b17 Desktop: Fixes #8072: Enter Key No Longer Saves and Closes The Tag Dialog 2023-05-08 17:11:58 +01:00
Laurent Cozic
3b836fdd61 Desktop: Fixes #8143: Fixes crash when using multiple profiles along with certain plugins 2023-05-08 17:10:32 +01:00
Laurent Cozic
f0afffedc9 Desktop: Fixes #8143: Fixes crash when using multiple profiles along with certain plugins 2023-05-08 17:10:20 +01:00
Laurent Cozic
6d8374885c Desktop release v2.10.16 2023-04-27 09:28:27 +01:00
Laurent Cozic
2e2feaba3d Desktop: Revert to "normal" package compression 2023-04-27 09:28:11 +01:00
Laurent Cozic
b84fc1c8b0 Desktop release v2.10.15 2023-04-26 21:49:44 +01:00
Laurent Cozic
18fef2d9df Desktop: Resolves #8028: Remove custom PDF viewer to reduce application size 2023-04-26 21:49:17 +01:00
Laurent Cozic
dfd0c40982 Desktop release v2.10.14 2023-04-26 12:23:05 +01:00
Arun Kumar
b514ca7e7d Desktop: Resolves #8028: Compress installer to reduce size (#8068) 2023-04-26 12:19:34 +01:00
9 changed files with 104 additions and 42 deletions

View File

@@ -631,7 +631,7 @@ const mapStateToProps = (state: AppState) => {
], whenClauseContext)[0], ], whenClauseContext)[0],
contentMaxWidth: state.settings['style.editor.contentMaxWidth'], contentMaxWidth: state.settings['style.editor.contentMaxWidth'],
isSafeMode: state.settings.isSafeMode, isSafeMode: state.settings.isSafeMode,
useCustomPdfViewer: state.settings.useCustomPdfViewer, useCustomPdfViewer: false, // state.settings.useCustomPdfViewer,
}; };
}; };

View File

@@ -26,11 +26,15 @@ export default class PromptDialog extends React.Component<Props, any> {
private focusInput_: boolean; private focusInput_: boolean;
private styles_: any; private styles_: any;
private styleKey_: string; private styleKey_: string;
private menuIsOpened_: boolean = false;
constructor(props: Props) { constructor(props: Props) {
super(props); super(props);
this.answerInput_ = React.createRef(); this.answerInput_ = React.createRef();
this.select_menuOpen = this.select_menuOpen.bind(this);
this.select_menuClose = this.select_menuClose.bind(this);
} }
UNSAFE_componentWillMount() { UNSAFE_componentWillMount() {
@@ -39,6 +43,7 @@ export default class PromptDialog extends React.Component<Props, any> {
answer: this.props.defaultValue ? this.props.defaultValue : '', answer: this.props.defaultValue ? this.props.defaultValue : '',
}); });
this.focusInput_ = true; this.focusInput_ = true;
this.menuIsOpened_ = false;
} }
UNSAFE_componentWillReceiveProps(newProps: Props) { UNSAFE_componentWillReceiveProps(newProps: Props) {
@@ -52,7 +57,15 @@ export default class PromptDialog extends React.Component<Props, any> {
} }
} }
componentDidUpdate() { private select_menuOpen() {
this.menuIsOpened_ = true;
}
private select_menuClose() {
this.menuIsOpened_ = false;
}
public componentDidUpdate() {
if (this.focusInput_ && this.answerInput_.current) this.answerInput_.current.focus(); if (this.focusInput_ && this.answerInput_.current) this.answerInput_.current.focus();
this.focusInput_ = false; this.focusInput_ = false;
} }
@@ -224,16 +237,14 @@ export default class PromptDialog extends React.Component<Props, any> {
const onKeyDown = (event: any) => { const onKeyDown = (event: any) => {
if (event.key === 'Enter') { if (event.key === 'Enter') {
if (this.props.inputType === 'tags' || this.props.inputType === 'dropdown') { // If the dropdown is open, we don't close the dialog - instead
// the currently item will be selcted. If it is closed however
// we confirm the dialog.
if ((this.props.inputType === 'tags' || this.props.inputType === 'dropdown') && this.menuIsOpened_) {
// Do nothing // Do nothing
} else { } else {
onClose(true); onClose(true);
} }
// } else if (this.answerInput_.current && !this.answerInput_.current.state.menuIsOpen) {
// // The menu will be open if the user is selecting a new item
// onClose(true);
// }
} else if (event.key === 'Escape') { } else if (event.key === 'Escape') {
onClose(false); onClose(false);
} }
@@ -246,9 +257,9 @@ export default class PromptDialog extends React.Component<Props, any> {
if (this.props.inputType === 'datetime') { if (this.props.inputType === 'datetime') {
inputComp = <Datetime className="datetime-picker" value={this.state.answer} inputProps={{ style: styles.input }} dateFormat={time.dateFormat()} timeFormat={time.timeFormat()} onChange={(momentObject: any) => onDateTimeChange(momentObject)} />; inputComp = <Datetime className="datetime-picker" value={this.state.answer} inputProps={{ style: styles.input }} dateFormat={time.dateFormat()} timeFormat={time.timeFormat()} onChange={(momentObject: any) => onDateTimeChange(momentObject)} />;
} else if (this.props.inputType === 'tags') { } else if (this.props.inputType === 'tags') {
inputComp = <CreatableSelect className="tag-selector" styles={styles.select} theme={styles.selectTheme} ref={this.answerInput_} value={this.state.answer} placeholder="" components={makeAnimated()} isMulti={true} isClearable={false} backspaceRemovesValue={true} options={this.props.autocomplete} onChange={onSelectChange} onKeyDown={(event: any) => onKeyDown(event)} />; inputComp = <CreatableSelect className="tag-selector" onMenuOpen={this.select_menuOpen} onMenuClose={this.select_menuClose} styles={styles.select} theme={styles.selectTheme} ref={this.answerInput_} value={this.state.answer} placeholder="" components={makeAnimated()} isMulti={true} isClearable={false} backspaceRemovesValue={true} options={this.props.autocomplete} onChange={onSelectChange} onKeyDown={(event: any) => onKeyDown(event)} />;
} else if (this.props.inputType === 'dropdown') { } else if (this.props.inputType === 'dropdown') {
inputComp = <Select className="item-selector" styles={styles.select} theme={styles.selectTheme} ref={this.answerInput_} components={makeAnimated()} value={this.props.answer} defaultValue={this.props.defaultValue} isClearable={false} options={this.props.autocomplete} onChange={onSelectChange} onKeyDown={(event: any) => onKeyDown(event)} />; inputComp = <Select className="item-selector" onMenuOpen={this.select_menuOpen} onMenuClose={this.select_menuClose} styles={styles.select} theme={styles.selectTheme} ref={this.answerInput_} components={makeAnimated()} value={this.props.answer} defaultValue={this.props.defaultValue} isClearable={false} options={this.props.autocomplete} onChange={onSelectChange} onKeyDown={(event: any) => onKeyDown(event)} />;
} else { } else {
inputComp = <input style={styles.input} ref={this.answerInput_} value={this.state.answer} type="text" onChange={event => onChange(event)} onKeyDown={event => onKeyDown(event)} />; inputComp = <input style={styles.input} ref={this.answerInput_} value={this.state.answer} type="text" onChange={event => onChange(event)} onKeyDown={event => onKeyDown(event)} />;
} }

View File

@@ -1,6 +1,6 @@
{ {
"name": "@joplin/app-desktop", "name": "@joplin/app-desktop",
"version": "2.10.13", "version": "2.10.17",
"description": "Joplin for Desktop", "description": "Joplin for Desktop",
"main": "main.js", "main": "main.js",
"private": true, "private": true,
@@ -27,6 +27,7 @@
}, },
"build": { "build": {
"appId": "net.cozic.joplin-desktop", "appId": "net.cozic.joplin-desktop",
"compression": "normal",
"productName": "Joplin", "productName": "Joplin",
"npmRebuild": false, "npmRebuild": false,
"afterSign": "./tools/notarizeMacApp.js", "afterSign": "./tools/notarizeMacApp.js",
@@ -137,7 +138,6 @@
"@fortawesome/fontawesome-free": "5.15.4", "@fortawesome/fontawesome-free": "5.15.4",
"@joeattardi/emoji-button": "4.6.4", "@joeattardi/emoji-button": "4.6.4",
"@joplin/lib": "~2.10", "@joplin/lib": "~2.10",
"@joplin/pdf-viewer": "~2.10",
"@joplin/renderer": "~2.10", "@joplin/renderer": "~2.10",
"async-mutex": "0.4.0", "async-mutex": "0.4.0",
"codemirror": "5.65.9", "codemirror": "5.65.9",

View File

@@ -72,10 +72,10 @@ async function main() {
src: langSourceDir, src: langSourceDir,
dest: `${buildLibDir}/tinymce/langs`, dest: `${buildLibDir}/tinymce/langs`,
}, },
{ // {
src: resolve(__dirname, '../../pdf-viewer/dist'), // src: resolve(__dirname, '../../pdf-viewer/dist'),
dest: `${buildLibDir}/@joplin/pdf-viewer`, // dest: `${buildLibDir}/@joplin/pdf-viewer`,
}, // },
]; ];
const files = [ const files = [
@@ -93,10 +93,10 @@ async function main() {
src: resolve(__dirname, '../../lib/services/plugins/sandboxProxy.js'), src: resolve(__dirname, '../../lib/services/plugins/sandboxProxy.js'),
dest: `${buildLibDir}/@joplin/lib/services/plugins/sandboxProxy.js`, dest: `${buildLibDir}/@joplin/lib/services/plugins/sandboxProxy.js`,
}, },
{ // {
src: resolve(__dirname, '../../pdf-viewer/index.html'), // src: resolve(__dirname, '../../pdf-viewer/index.html'),
dest: `${buildLibDir}/@joplin/pdf-viewer/index.html`, // dest: `${buildLibDir}/@joplin/pdf-viewer/index.html`,
}, // },
]; ];
// First we delete all the destination directories, then we copy the files. // First we delete all the destination directories, then we copy the files.

View File

@@ -1,4 +1,4 @@
import Setting, { SettingSectionSource, SettingStorage } from '../models/Setting'; import Setting, { SettingItemType, SettingSectionSource, SettingStorage } from '../models/Setting';
import { setupDatabaseAndSynchronizer, switchClient, expectThrow, expectNotThrow, msleep } from '../testing/test-utils'; import { setupDatabaseAndSynchronizer, switchClient, expectThrow, expectNotThrow, msleep } from '../testing/test-utils';
import { readFile, stat, mkdirp, writeFile, pathExists, readdir } from 'fs-extra'; import { readFile, stat, mkdirp, writeFile, pathExists, readdir } from 'fs-extra';
import Logger from '../Logger'; import Logger from '../Logger';
@@ -297,12 +297,21 @@ describe('models/Setting', () => {
expect(Setting.isSet('spellChecker.languages')).toBe(false); expect(Setting.isSet('spellChecker.languages')).toBe(false);
})); }));
it('should load sub-profile settings - 1', async () => { it('should load sub-profile settings', async () => {
await Setting.reset(); await Setting.reset();
await Setting.registerSetting('non_builtin', {
public: true,
storage: SettingStorage.File,
isGlobal: true,
type: SettingItemType.Bool,
value: false,
});
Setting.setValue('locale', 'fr_FR'); // Global setting Setting.setValue('locale', 'fr_FR'); // Global setting
Setting.setValue('theme', Setting.THEME_DARK); // Global setting Setting.setValue('theme', Setting.THEME_DARK); // Global setting
Setting.setValue('sync.target', 9); // Local setting Setting.setValue('sync.target', 9); // Local setting
Setting.setValue('non_builtin', true); // Local setting
await Setting.saveAll(); await Setting.saveAll();
await switchToSubProfileSettings(); await switchToSubProfileSettings();
@@ -311,6 +320,9 @@ describe('models/Setting', () => {
expect(Setting.value('theme')).toBe(Setting.THEME_DARK); // Should come from the root profile expect(Setting.value('theme')).toBe(Setting.THEME_DARK); // Should come from the root profile
expect(Setting.value('sync.target')).toBe(0); // Should come from the local profile expect(Setting.value('sync.target')).toBe(0); // Should come from the local profile
// Non-built-in variables are not copied
expect(() => Setting.value('non_builtin')).toThrow();
// Also check that the special loadOne() function works as expected // Also check that the special loadOne() function works as expected
expect((await Setting.loadOne('locale')).value).toBe('fr_FR'); expect((await Setting.loadOne('locale')).value).toBe('fr_FR');
@@ -318,7 +330,7 @@ describe('models/Setting', () => {
expect((await Setting.loadOne('sync.target')).value).toBe(undefined); expect((await Setting.loadOne('sync.target')).value).toBe(undefined);
}); });
it('should save sub-profile settings - 2', async () => { it('should save sub-profile settings', async () => {
await Setting.reset(); await Setting.reset();
Setting.setValue('locale', 'fr_FR'); // Global setting Setting.setValue('locale', 'fr_FR'); // Global setting
Setting.setValue('theme', Setting.THEME_DARK); // Global setting Setting.setValue('theme', Setting.THEME_DARK); // Global setting

View File

@@ -9,6 +9,7 @@ import FileHandler, { SettingValues } from './settings/FileHandler';
import Logger from '../Logger'; import Logger from '../Logger';
import mergeGlobalAndLocalSettings from '../services/profileConfig/mergeGlobalAndLocalSettings'; import mergeGlobalAndLocalSettings from '../services/profileConfig/mergeGlobalAndLocalSettings';
import splitGlobalAndLocalSettings from '../services/profileConfig/splitGlobalAndLocalSettings'; import splitGlobalAndLocalSettings from '../services/profileConfig/splitGlobalAndLocalSettings';
import JoplinError from '../JoplinError';
const { sprintf } = require('sprintf-js'); const { sprintf } = require('sprintf-js');
const ObjectUtils = require('../ObjectUtils'); const ObjectUtils = require('../ObjectUtils');
const { toTitleCase } = require('../string-utils.js'); const { toTitleCase } = require('../string-utils.js');
@@ -312,6 +313,7 @@ class Setting extends BaseModel {
private static fileHandler_: FileHandler = null; private static fileHandler_: FileHandler = null;
private static rootFileHandler_: FileHandler = null; private static rootFileHandler_: FileHandler = null;
private static settingFilename_: string = 'settings.json'; private static settingFilename_: string = 'settings.json';
private static buildInMetadata_: SettingItems = null;
static tableName() { static tableName() {
return 'settings'; return 'settings';
@@ -406,7 +408,7 @@ class Setting extends BaseModel {
return output; return output;
}; };
this.metadata_ = { this.buildInMetadata_ = {
'clientId': { 'clientId': {
value: '', value: '',
type: SettingItemType.String, type: SettingItemType.String,
@@ -1384,7 +1386,7 @@ class Setting extends BaseModel {
useCustomPdfViewer: { useCustomPdfViewer: {
value: false, value: false,
type: SettingItemType.Bool, type: SettingItemType.Bool,
public: true, public: false,
advanced: true, advanced: true,
appTypes: [AppType.Desktop], appTypes: [AppType.Desktop],
label: () => 'Use custom PDF viewer (Beta)', label: () => 'Use custom PDF viewer (Beta)',
@@ -1685,6 +1687,8 @@ class Setting extends BaseModel {
}; };
this.metadata_ = { ...this.buildInMetadata_ };
this.metadata_ = Object.assign(this.metadata_, this.customMetadata_); this.metadata_ = Object.assign(this.metadata_, this.customMetadata_);
if (this.constants_.env === Env.Dev) this.validateMetadata(this.metadata_); if (this.constants_.env === Env.Dev) this.validateMetadata(this.metadata_);
@@ -1698,6 +1702,10 @@ class Setting extends BaseModel {
} }
} }
public static isBuiltinKey(key: string): boolean {
return key in this.buildInMetadata_;
}
public static customCssFilePath(filename: string): string { public static customCssFilePath(filename: string): string {
return `${this.value('rootProfileDir')}/${filename}`; return `${this.value('rootProfileDir')}/${filename}`;
} }
@@ -1799,7 +1807,7 @@ class Setting extends BaseModel {
static settingMetadata(key: string): SettingItem { static settingMetadata(key: string): SettingItem {
const metadata = this.metadata(); const metadata = this.metadata();
if (!(key in metadata)) throw new Error(`Unknown key: ${key}`); if (!(key in metadata)) throw new JoplinError(`Unknown key: ${key}`, 'unknown_key');
const output = Object.assign({}, metadata[key]); const output = Object.assign({}, metadata[key]);
output.key = key; output.key = key;
return output; return output;
@@ -2244,7 +2252,7 @@ class Setting extends BaseModel {
static enumOptions(key: string) { static enumOptions(key: string) {
const metadata = this.metadata(); const metadata = this.metadata();
if (!metadata[key]) throw new Error(`Unknown key: ${key}`); if (!metadata[key]) throw new JoplinError(`Unknown key: ${key}`, 'unknown_key');
if (!metadata[key].options) throw new Error(`No options for: ${key}`); if (!metadata[key].options) throw new Error(`No options for: ${key}`);
return metadata[key].options(); return metadata[key].options();
} }

View File

@@ -1,20 +1,52 @@
import Logger from '../../Logger';
import Setting from '../../models/Setting'; import Setting from '../../models/Setting';
const logger = Logger.create('mergeGlobalAndLocalSettings');
export default (rootSettings: Record<string, any>, subProfileSettings: Record<string, any>) => { export default (rootSettings: Record<string, any>, subProfileSettings: Record<string, any>) => {
const output: Record<string, any> = { ...subProfileSettings }; const output: Record<string, any> = { ...subProfileSettings };
for (const k of Object.keys(output)) { for (const k of Object.keys(output)) {
const md = Setting.settingMetadata(k); try {
if (md.isGlobal) { const md = Setting.settingMetadata(k);
delete output[k]; if (md.isGlobal) {
if (k in rootSettings) output[k] = rootSettings[k]; delete output[k];
if (k in rootSettings) output[k] = rootSettings[k];
}
} catch (error) {
if (error.code === 'unknown_key') {
// The root settings may contain plugin parameters, but the
// sub-profile won't necessarily have these plugins. In that
// case, the app will throw an error, but we can ignore it since
// we don't need this particular setting.
// https://github.com/laurent22/joplin/issues/8143
logger.info(`Ignoring unknown key in root settings: ${k}`);
}
} }
} }
for (const k of Object.keys(rootSettings)) { for (const k of Object.keys(rootSettings)) {
const md = Setting.settingMetadata(k); // We only copy built-in key and not, for example, plugin keys, because
if (md.isGlobal) { // those are plugin-specific
output[k] = rootSettings[k]; if (!Setting.isBuiltinKey(k)) {
logger.info(`Skipping non-built-in key: ${k}`);
continue;
}
try {
const md = Setting.settingMetadata(k);
if (md.isGlobal) {
output[k] = rootSettings[k];
}
} catch (error) {
if (error.code === 'unknown_key') {
// The root settings may contain plugin parameters, but the
// sub-profile won't necessarily have these plugins. In that
// case, the app will throw an error, but we can ignore it since
// we don't need this particular setting.
// https://github.com/laurent22/joplin/issues/8143
logger.info(`Ignoring unknown key in root settings: ${k}`);
}
} }
} }

View File

@@ -9,12 +9,12 @@
"access": "restricted" "access": "restricted"
}, },
"scripts": { "scripts": {
"tsc": "tsc --project tsconfig.json", "tsc_DISABLED": "tsc --project tsconfig.json",
"watch": "webpack --watch --config webpack.config.js --mode=development", "watch_DISABLED": "webpack --watch --config webpack.config.js --mode=development",
"build": "webpack --config webpack.config.js --mode=production", "build_DISABLED": "webpack --config webpack.config.js --mode=production",
"test": "jest", "test_DISABLED": "jest",
"test-ci": "yarn test", "test-ci_DISABLED": "yarn test",
"postinstall": "yarn build" "postinstall_DISABLED": "yarn build"
}, },
"author": "Joplin", "author": "Joplin",
"license": "AGPL-3.0-or-later", "license": "AGPL-3.0-or-later",

View File

@@ -4644,7 +4644,6 @@ __metadata:
"@fortawesome/fontawesome-free": 5.15.4 "@fortawesome/fontawesome-free": 5.15.4
"@joeattardi/emoji-button": 4.6.4 "@joeattardi/emoji-button": 4.6.4
"@joplin/lib": ~2.10 "@joplin/lib": ~2.10
"@joplin/pdf-viewer": ~2.10
"@joplin/renderer": ~2.10 "@joplin/renderer": ~2.10
"@joplin/tools": ~2.10 "@joplin/tools": ~2.10
"@testing-library/react-hooks": 8.0.1 "@testing-library/react-hooks": 8.0.1
@@ -4948,7 +4947,7 @@ __metadata:
languageName: unknown languageName: unknown
linkType: soft linkType: soft
"@joplin/pdf-viewer@workspace:packages/pdf-viewer, @joplin/pdf-viewer@~2.10": "@joplin/pdf-viewer@workspace:packages/pdf-viewer":
version: 0.0.0-use.local version: 0.0.0-use.local
resolution: "@joplin/pdf-viewer@workspace:packages/pdf-viewer" resolution: "@joplin/pdf-viewer@workspace:packages/pdf-viewer"
dependencies: dependencies: