diff --git a/packages/app-desktop/gui/ConfigScreen/ConfigScreen.tsx b/packages/app-desktop/gui/ConfigScreen/ConfigScreen.tsx index 866006636c..20a74e19e6 100644 --- a/packages/app-desktop/gui/ConfigScreen/ConfigScreen.tsx +++ b/packages/app-desktop/gui/ConfigScreen/ConfigScreen.tsx @@ -125,19 +125,6 @@ class ConfigScreenComponent extends React.Component { this.switchSection(event.section.name); } - keyValueToArray(kv: any) { - const output = []; - for (const k in kv) { - if (!kv.hasOwnProperty(k)) continue; - output.push({ - key: k, - label: kv[k], - }); - } - - return output; - } - renderSectionDescription(section: any) { const description = Setting.sectionDescription(section.name); if (!description) return null; @@ -376,7 +363,11 @@ class ConfigScreenComponent extends React.Component { } else if (md.isEnum) { const items = []; const settingOptions = md.options(); - const array = this.keyValueToArray(settingOptions); + const array = Setting.enumOptionsToValueLabels(settingOptions, md.optionsOrder ? md.optionsOrder() : [], { + valueKey: 'key', + labelKey: 'label', + }); + for (let i = 0; i < array.length; i++) { const e = array[i]; items.push( diff --git a/packages/app-mobile/components/screens/ConfigScreen.tsx b/packages/app-mobile/components/screens/ConfigScreen.tsx index 7ad8dd8832..19812f62a8 100644 --- a/packages/app-mobile/components/screens/ConfigScreen.tsx +++ b/packages/app-mobile/components/screens/ConfigScreen.tsx @@ -413,12 +413,7 @@ class ConfigScreenComponent extends BaseScreenComponent { if (md.isEnum) { value = value.toString(); - const items = []; - const settingOptions = md.options(); - for (const k in settingOptions) { - if (!settingOptions.hasOwnProperty(k)) continue; - items.push({ label: settingOptions[k], value: k.toString() }); - } + const items = Setting.enumOptionsToValueLabels(md.options(), md.optionsOrder ? md.optionsOrder() : []); return ( diff --git a/packages/lib/SyncTargetRegistry.ts b/packages/lib/SyncTargetRegistry.ts index 40126e07da..d28351c62d 100644 --- a/packages/lib/SyncTargetRegistry.ts +++ b/packages/lib/SyncTargetRegistry.ts @@ -83,16 +83,15 @@ export default class SyncTargetRegistry { } return output; - - // const sorted: Record = {}; - // for (const o of syncTargetOrder) { - // sorted[o] = output[o]; - // } - - // for (const [name, value] of Object.entries(output)) { - // if (!sorted[name]) sorted[name] = value; - // } - - // return sorted; } + + public static optionsOrder(): string[] { + return [ + '0', // None + '10', // Joplin Cloud + '7', // Dropbox + '3', // OneDrive + ]; + } + } diff --git a/packages/lib/models/Setting.ts b/packages/lib/models/Setting.ts index 6cf22f9c66..012e4fa691 100644 --- a/packages/lib/models/Setting.ts +++ b/packages/lib/models/Setting.ts @@ -25,6 +25,11 @@ export enum SettingItemType { Button = 6, } +interface OptionsToValueLabelsOptions { + valueKey: string; + labelKey: string; +} + export enum SettingItemSubType { FilePathAndArgs = 'file_path_and_args', FilePath = 'file_path', // Not supported on mobile! @@ -53,6 +58,7 @@ export interface SettingItem { label?(): string; description?: Function; options?(): any; + optionsOrder?(): string[]; appTypes?: AppType[]; show?(settings: any): boolean; filter?(value: any): any; @@ -421,6 +427,9 @@ class Setting extends BaseModel { options: () => { return SyncTargetRegistry.idAndLabelPlainObject(platform); }, + optionsOrder: () => { + return SyncTargetRegistry.optionsOrder(); + }, storage: SettingStorage.File, }, @@ -905,7 +914,7 @@ class Setting extends BaseModel { }, 'notes.sortOrder.reverse': { value: true, type: SettingItemType.Bool, storage: SettingStorage.File, isGlobal: true, section: 'note', public: true, label: () => _('Reverse sort order'), appTypes: [AppType.Cli] }, // NOTE: A setting whose name starts with 'notes.sortOrder' is special, - // which implies changing the setting automatically triggers the reflesh of notes. + // which implies changing the setting automatically triggers the refresh of notes. // See lib/BaseApplication.ts/generalMiddleware() for details. 'notes.sortOrder.buttonsVisible': { value: true, @@ -1735,7 +1744,7 @@ class Setting extends BaseModel { // Keys in the database takes precedence over keys in the keychain because // they are more likely to be up to date (saving to keychain can fail, but // saving to database shouldn't). When the keychain works, the secure keys - // are deleted from the database and transfered to the keychain in saveAll(). + // are deleted from the database and transferred to the keychain in saveAll(). const rowKeys = rows.map((r: any) => r.key); const secureKeys = this.keys(false, null, { secureOnly: true }); @@ -1901,6 +1910,35 @@ class Setting extends BaseModel { } } + public static enumOptionsToValueLabels(enumOptions: Record, order: string[], options: OptionsToValueLabelsOptions = null) { + options = { + labelKey: 'label', + valueKey: 'value', + ...options, + }; + + const output = []; + + for (const value of order) { + output.push({ + [options.valueKey]: value, + [options.labelKey]: enumOptions[value], + }); + } + + for (const k in enumOptions) { + if (!enumOptions.hasOwnProperty(k)) continue; + if (order.includes(k)) continue; + + output.push({ + [options.valueKey]: k, + [options.labelKey]: enumOptions[k], + }); + } + + return output; + } + static valueToString(key: string, value: any) { const md = this.settingMetadata(key); value = this.formatValue(key, value); @@ -2078,7 +2116,7 @@ class Setting extends BaseModel { // We need to be careful here because there's a bug in the macOS keychain that can // make it fail to save a password. https://github.com/desktop/desktop/issues/3263 // So we try to set it and if it fails, we set it on the database instead. This is not - // ideal because they won't be crypted, but better than losing all the user's passwords. + // ideal because they won't be encrypted, but better than losing all the user's passwords. // The passwords would be set again on the keychain once it starts working again (probably // after the user switch their computer off and on again). //