diff --git a/packages/app-cli/tests/support/plugins/settings/src/index.ts b/packages/app-cli/tests/support/plugins/settings/src/index.ts index 37b29c4f31..3ce79d92f8 100644 --- a/packages/app-cli/tests/support/plugins/settings/src/index.ts +++ b/packages/app-cli/tests/support/plugins/settings/src/index.ts @@ -8,25 +8,46 @@ joplin.plugins.register({ iconName: 'fas fa-music', }); - await joplin.settings.registerSetting('myCustomSetting', { - value: 123, - type: SettingItemType.Int, - section: 'myCustomSection', - public: true, - label: 'My Custom Setting', - }); + await joplin.settings.registerSettings({ + 'myCustomSetting': { + value: 123, + type: SettingItemType.Int, + section: 'myCustomSection', + public: true, + label: 'My Custom Setting', + }, - await joplin.settings.registerSetting('multiOptionTest', { - value: 'en', - type: SettingItemType.String, - section: 'myCustomSection', - isEnum: true, - public: true, - label: 'Multi-options test', - options: { - 'en': 'English', - 'fr': 'French', - 'es': 'Spanish', + 'multiOptionTest': { + value: 'en', + type: SettingItemType.String, + section: 'myCustomSection', + isEnum: true, + public: true, + label: 'Multi-options test', + options: { + 'en': 'English', + 'fr': 'French', + 'es': 'Spanish', + }, + }, + + 'mySecureSetting': { + value: 'hunter2', + type: SettingItemType.String, + section: 'myCustomSection', + public: true, + secure: true, + label: 'My Secure Setting', + }, + + 'myFileSetting': { + value: 'abcd', + type: SettingItemType.String, + section: 'myCustomSection', + public: true, + label: 'My file setting', + description: 'This setting will be saved to settings.json', + ['storage' as any]: 2, // Should be `storage: SettingStorage.File` }, }); @@ -47,7 +68,11 @@ joplin.plugins.register({ iconName: 'fas fa-drum', execute: async () => { const value = await joplin.settings.value('myCustomSetting'); - alert('Current value is: ' + value); + console.info('Current value is: ' + value); + const secureValue = await joplin.settings.value('mySecureSetting'); + console.info('Secure value is: ' + secureValue); + const fileValue = await joplin.settings.value('myFileSetting'); + console.info('Setting in file is: ' + fileValue); }, }); diff --git a/packages/app-desktop/testPluginDemo.sh b/packages/app-desktop/testPluginDemo.sh index 2a9977129f..7dffb7c4a7 100755 --- a/packages/app-desktop/testPluginDemo.sh +++ b/packages/app-desktop/testPluginDemo.sh @@ -4,5 +4,5 @@ # It could be used to develop plugins too. SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" -PLUGIN_PATH="$SCRIPT_DIR/../app-cli/tests/support/plugins/external_assets" +PLUGIN_PATH="$SCRIPT_DIR/../app-cli/tests/support/plugins/settings" npm i --prefix="$PLUGIN_PATH" && npm start -- --dev-plugins "$PLUGIN_PATH" \ No newline at end of file diff --git a/packages/lib/models/Setting.ts b/packages/lib/models/Setting.ts index 7bde97c7df..a01273c104 100644 --- a/packages/lib/models/Setting.ts +++ b/packages/lib/models/Setting.ts @@ -1363,10 +1363,18 @@ class Setting extends BaseModel { } // Low-level method to load a setting directly from the database. Should not be used in most cases. - public static async loadOne(key: string) { + public static async loadOne(key: string): Promise { if (this.keyStorage(key) === SettingStorage.File) { const fromFile = await this.fileHandler.load(); - return fromFile[key]; + return { + key, + value: fromFile[key], + }; + } else if (this.settingMetadata(key).secure) { + return { + key, + value: await this.keychainService().password(`setting.${key}`), + }; } else { return this.modelSelectOne('SELECT * FROM settings WHERE key = ?', [key]); } diff --git a/packages/lib/services/plugins/api/JoplinSettings.ts b/packages/lib/services/plugins/api/JoplinSettings.ts index 53e856bca7..d7585a9046 100644 --- a/packages/lib/services/plugins/api/JoplinSettings.ts +++ b/packages/lib/services/plugins/api/JoplinSettings.ts @@ -65,6 +65,7 @@ export default class JoplinSettings { if ('minimum' in setting) internalSettingItem.minimum = setting.minimum; if ('maximum' in setting) internalSettingItem.maximum = setting.maximum; if ('step' in setting) internalSettingItem.step = setting.step; + if ('storage' in setting) internalSettingItem.storage = setting.storage; await Setting.registerSetting(this.namespacedKey(key), internalSettingItem); } diff --git a/packages/lib/services/plugins/api/types.ts b/packages/lib/services/plugins/api/types.ts index 9c4aa73320..a798b11c32 100644 --- a/packages/lib/services/plugins/api/types.ts +++ b/packages/lib/services/plugins/api/types.ts @@ -334,6 +334,11 @@ export enum SettingItemType { Button = 6, } +export enum SettingStorage { + Database = 1, + File = 2, +} + // Redefine a simplified interface to mask internal details // and to remove function calls as they would have to be async. export interface SettingItem { @@ -393,6 +398,11 @@ export interface SettingItem { minimum?: number; maximum?: number; step?: number; + + /** + * Either store the setting in the database or in settings.json. Defaults to database. + */ + storage?: SettingStorage; } export interface SettingSection {