From ab82cf783e6c3525210f3e633d31b1cca2f1e58c Mon Sep 17 00:00:00 2001 From: EnixCoda Date: Mon, 24 May 2021 20:51:07 +0800 Subject: [PATCH] refactor: destruct config helper --- src/components/SimpleToggleField.tsx | 2 +- src/components/settings/FileTreeSettings.tsx | 2 +- src/components/settings/SidebarSettings.tsx | 2 +- src/containers/ConfigsContext.tsx | 7 +- src/driver/core/FileExplorer.ts | 2 +- src/utils/config/helper.ts | 81 +++++++++ src/utils/config/migrations/1.0.1.ts | 23 +++ src/utils/config/migrations/1.3.4.ts | 28 +++ src/utils/config/migrations/2.6.0.ts | 41 +++++ src/utils/config/migrations/index.ts | 18 ++ src/utils/configHelper.ts | 178 ------------------- src/utils/storageHelper.ts | 15 +- 12 files changed, 211 insertions(+), 188 deletions(-) create mode 100644 src/utils/config/helper.ts create mode 100644 src/utils/config/migrations/1.0.1.ts create mode 100644 src/utils/config/migrations/1.3.4.ts create mode 100644 src/utils/config/migrations/2.6.0.ts create mode 100644 src/utils/config/migrations/index.ts delete mode 100644 src/utils/configHelper.ts diff --git a/src/components/SimpleToggleField.tsx b/src/components/SimpleToggleField.tsx index 2e05697..db4bfc7 100644 --- a/src/components/SimpleToggleField.tsx +++ b/src/components/SimpleToggleField.tsx @@ -1,6 +1,6 @@ import { useConfigs } from 'containers/ConfigsContext' import * as React from 'react' -import { Config } from 'utils/configHelper' +import { Config } from 'utils/config/helper' import { Field } from './settings/Field' export type SimpleField = { diff --git a/src/components/settings/FileTreeSettings.tsx b/src/components/settings/FileTreeSettings.tsx index 72c3ca7..d28154c 100644 --- a/src/components/settings/FileTreeSettings.tsx +++ b/src/components/settings/FileTreeSettings.tsx @@ -2,7 +2,7 @@ import { wikiLinks } from 'components/settings/SettingsBar' import { SimpleToggleField } from 'components/SimpleToggleField' import { useConfigs } from 'containers/ConfigsContext' import * as React from 'react' -import { Config } from 'utils/configHelper' +import { Config } from 'utils/config/helper' import { Option, SelectInput } from '../SelectInput' import { Field } from './Field' import { SettingsSection } from './SettingsSection' diff --git a/src/components/settings/SidebarSettings.tsx b/src/components/settings/SidebarSettings.tsx index 5707319..031b605 100644 --- a/src/components/settings/SidebarSettings.tsx +++ b/src/components/settings/SidebarSettings.tsx @@ -3,7 +3,7 @@ import { Option, SelectInput } from 'components/SelectInput' import { SimpleToggleField } from 'components/SimpleToggleField' import { useConfigs } from 'containers/ConfigsContext' import * as React from 'react' -import { Config } from 'utils/configHelper' +import { Config } from 'utils/config/helper' import { friendlyFormatShortcut } from 'utils/general' import { useStateIO } from 'utils/hooks/useStateIO' import * as keyHelper from 'utils/keyHelper' diff --git a/src/containers/ConfigsContext.tsx b/src/containers/ConfigsContext.tsx index c5291b6..90c39b1 100644 --- a/src/containers/ConfigsContext.tsx +++ b/src/containers/ConfigsContext.tsx @@ -1,6 +1,5 @@ import * as React from 'react' -import * as configsHelper from 'utils/configHelper' -import { Config } from 'utils/configHelper' +import { Config, configHelper } from 'utils/config/helper' type Props = {} @@ -12,12 +11,12 @@ export const ConfigsContext = React.createContext(null) export function ConfigsContextWrapper(props: React.PropsWithChildren) { const [configs, setConfigs] = React.useState(null) React.useEffect(() => { - configsHelper.get().then(setConfigs) + configHelper.get().then(setConfigs) }, []) const onChange = React.useCallback( (updatedConfigs: Partial) => { const mergedConfigs = { ...configs, ...updatedConfigs } as Config - configsHelper.set(mergedConfigs) + configHelper.set(mergedConfigs) setConfigs(mergedConfigs) }, [configs, setConfigs], diff --git a/src/driver/core/FileExplorer.ts b/src/driver/core/FileExplorer.ts index 69ce519..66c8bab 100644 --- a/src/driver/core/FileExplorer.ts +++ b/src/driver/core/FileExplorer.ts @@ -1,7 +1,7 @@ import { SideBarStateContextShape } from 'components/SideBarState' import { GetCreatedMethod, MethodCreator } from 'driver/connect' import { platform } from 'platforms' -import { Config } from 'utils/configHelper' +import { Config } from 'utils/config/helper' import * as DOMHelper from 'utils/DOMHelper' import { VisibleNodes, VisibleNodesGenerator } from 'utils/VisibleNodesGenerator' diff --git a/src/utils/config/helper.ts b/src/utils/config/helper.ts new file mode 100644 index 0000000..a3e6682 --- /dev/null +++ b/src/utils/config/helper.ts @@ -0,0 +1,81 @@ +import { SearchMode } from 'components/searchModes' +import { storageHelper } from 'utils/storageHelper' +import { migrateConfig } from './migrations' + +export type Config = { + sideBarWidth: number + shortcut: string | undefined + accessToken: string | undefined + compressSingletonFolder: boolean + copyFileButton: boolean + copySnippetButton: boolean + intelligentToggle: boolean | null // `null` stands for intelligent, boolean for sidebar open state + icons: 'rich' | 'dim' | 'native' + toggleButtonVerticalDistance: number + toggleButtonContent: 'logo' | 'octoface' + recursiveToggleFolder: 'shift' | 'alt' + searchMode: SearchMode + sidebarToggleMode: 'persistent' | 'float' +} + +enum configKeys { + sideBarWidth = 'sideBarWidth', + shortcut = 'shortcut', + accessToken = 'accessToken', + compressSingletonFolder = 'compressSingletonFolder', + copyFileButton = 'copyFileButton', + copySnippetButton = 'copySnippetButton', + intelligentToggle = 'intelligentToggle', + icons = 'icons', + toggleButtonVerticalDistance = 'toggleButtonVerticalDistance', + toggleButtonContent = 'toggleButtonContent', + recursiveToggleFolder = 'recursiveToggleFolder', + searchMode = 'searchMode', + sidebarToggleMode = 'sidebarToggleMode', +} + +const defaultConfigs: Config = { + sideBarWidth: 260, + shortcut: undefined, + accessToken: '', + compressSingletonFolder: true, + copyFileButton: true, + copySnippetButton: true, + intelligentToggle: null, + icons: 'rich', + toggleButtonVerticalDistance: 124, // align with GitHub's navbar items + toggleButtonContent: 'logo', + recursiveToggleFolder: 'shift', + searchMode: 'fuzzy', + sidebarToggleMode: 'float', +} + +const configKeyArray = Object.values(configKeys) + +function applyDefaultConfigs(configs: Partial) { + return configKeyArray.reduce((applied, key) => { + Object.assign(applied, { [key]: key in configs ? configs[key] : defaultConfigs[key] }) + return applied + }, {} as Config) +} + +export type VersionedConfig = Record & { configVersion: string } + +// do NOT use platform name +const platformStorageKey = `platform_` + window.location.host.toLowerCase() +const prepareConfig = new Promise(async resolve => { + await migrateConfig() + resolve() +}) + +async function get(): Promise { + await prepareConfig + const config = await storageHelper.get>([platformStorageKey]) + return applyDefaultConfigs(config?.[platformStorageKey] || {}) +} + +async function set(config: Config) { + return await storageHelper.set({ [platformStorageKey]: config }) +} + +export const configHelper = { get, set } diff --git a/src/utils/config/migrations/1.0.1.ts b/src/utils/config/migrations/1.0.1.ts new file mode 100644 index 0000000..7f16c3d --- /dev/null +++ b/src/utils/config/migrations/1.0.1.ts @@ -0,0 +1,23 @@ +import { storageHelper } from 'utils/storageHelper' +import { Migration } from '.' +import { Storage } from '../../storageHelper' + +export const migration: Migration = { + version: '1.0.1', + async migrate(version) { + const config: any | void = await storageHelper.get([ + 'configVersion', + 'sideBarWidth', + 'shortcut', + 'access_token', + 'compressSingletonFolder', + 'copyFileButton', + 'copySnippetButton', + 'intelligentToggle', + 'icons', + ]) + if (config && (!('configVersion' in config) || config.configVersion < version)) { + await storageHelper.set({ platform_GitHub: config, configVersion: version }) + } + }, +} diff --git a/src/utils/config/migrations/1.3.4.ts b/src/utils/config/migrations/1.3.4.ts new file mode 100644 index 0000000..9fd8cd9 --- /dev/null +++ b/src/utils/config/migrations/1.3.4.ts @@ -0,0 +1,28 @@ +import { storageHelper } from 'utils/storageHelper' +import { Migration } from '.' +import { Storage } from '../../storageHelper' +import { Config, VersionedConfig } from '../helper' + +export const migration: Migration = { + version: '1.3.4', + async migrate(version) { + const config: any | void = await storageHelper.get & Storage>([ + 'configVersion', + 'platform_undefined', + 'platform_GitHub', + 'platform_github.com', + ]) + if ( + config && + 'configVersion' in config && + config.configVersion < version && + (config.platform_GitHub || config.platform_undefined) && + !config['platform_github.com'] + ) { + await storageHelper.set({ + ['platform_github.com']: config.platform_GitHub || config.platform_undefined, + configVersion: version, + }) + } + }, +} diff --git a/src/utils/config/migrations/2.6.0.ts b/src/utils/config/migrations/2.6.0.ts new file mode 100644 index 0000000..ff3cca5 --- /dev/null +++ b/src/utils/config/migrations/2.6.0.ts @@ -0,0 +1,41 @@ +import { storageHelper } from 'utils/storageHelper' +import { Migration } from '.' +import { Storage } from '../../storageHelper' +import { VersionedConfig } from '../helper' + +export const migration: Migration = { + version: '2.6.0', + async migrate(version) { + type ConfigBeforeMigrate = { + access_token?: string + } + type ConfigAfterMigrate = { + accessToken?: string + } + + const config = await storageHelper.get & Storage>() + if (config && config.configVersion < version) { + const { configVersion, ...restConfig } = config + for (const key of Object.keys(restConfig)) { + if ( + typeof restConfig[key] === 'object' && + restConfig[key] && + 'access_token' in restConfig[key] + ) { + const config: ConfigBeforeMigrate = restConfig[key] + const { access_token: accessToken, ...legacy } = config + const migrated: ConfigAfterMigrate = { + ...legacy, + accessToken, + } + await storageHelper.set({ + [key]: migrated, + }) + } + } + await storageHelper.set({ + configVersion: version, + }) + } + }, +} diff --git a/src/utils/config/migrations/index.ts b/src/utils/config/migrations/index.ts new file mode 100644 index 0000000..7daa138 --- /dev/null +++ b/src/utils/config/migrations/index.ts @@ -0,0 +1,18 @@ +import { storageHelper } from 'utils/storageHelper' +import { Storage } from '../../storageHelper' +import { migration as v1v0v1 } from './1.0.1' +import { migration as v1v3v4 } from './1.3.4' +import { migration as v2v6v0 } from './2.6.0' + +export type Migration = { + version: string + migrate(version: Migration['version']): Async +} + +export async function migrateConfig() { + const migrations: Migration[] = [v1v0v1, v1v3v4, v2v6v0] + + for (const { version, migrate } of migrations) { + await migrate(version) + } +} diff --git a/src/utils/configHelper.ts b/src/utils/configHelper.ts deleted file mode 100644 index f949e85..0000000 --- a/src/utils/configHelper.ts +++ /dev/null @@ -1,178 +0,0 @@ -import { SearchMode } from 'components/searchModes' -import * as storageHelper from 'utils/storageHelper' - -export type Config = { - sideBarWidth: number - shortcut: string | undefined - accessToken: string | undefined - compressSingletonFolder: boolean - copyFileButton: boolean - copySnippetButton: boolean - intelligentToggle: boolean | null // `null` stands for intelligent, boolean for sidebar open state - icons: 'rich' | 'dim' | 'native' - toggleButtonVerticalDistance: number - toggleButtonContent: 'logo' | 'octoface' - recursiveToggleFolder: 'shift' | 'alt' - searchMode: SearchMode - sidebarToggleMode: 'persistent' | 'float' -} - -enum configKeys { - sideBarWidth = 'sideBarWidth', - shortcut = 'shortcut', - accessToken = 'accessToken', - compressSingletonFolder = 'compressSingletonFolder', - copyFileButton = 'copyFileButton', - copySnippetButton = 'copySnippetButton', - intelligentToggle = 'intelligentToggle', - icons = 'icons', - toggleButtonVerticalDistance = 'toggleButtonVerticalDistance', - toggleButtonContent = 'toggleButtonContent', - recursiveToggleFolder = 'recursiveToggleFolder', - searchMode = 'searchMode', - sidebarToggleMode = 'sidebarToggleMode', -} - -const defaultConfigs: Config = { - sideBarWidth: 260, - shortcut: undefined, - accessToken: '', - compressSingletonFolder: true, - copyFileButton: true, - copySnippetButton: true, - intelligentToggle: null, - icons: 'rich', - toggleButtonVerticalDistance: 124, // align with GitHub's navbar items - toggleButtonContent: 'logo', - recursiveToggleFolder: 'shift', - searchMode: 'fuzzy', - sidebarToggleMode: 'float', -} - -const configKeyArray = Object.values(configKeys) - -function applyDefaultConfigs(configs: Partial) { - return configKeyArray.reduce((applied, key) => { - Object.assign(applied, { [key]: key in configs ? configs[key] : defaultConfigs[key] }) - return applied - }, {} as Config) -} - -type VersionedConfig = Record & { configVersion: string } - -type Storage = { - // save root level `configVersion` for easier future migrating - [key in 'configVersion' | string]: string - - // separate different platform configs to simplify interactions with browser storage API - // e.g. - // platform_github.com?: Config -} - -async function migrateConfig() { - // not referencing to enum above to prevent migrate future configs - const migrations: { - version: string - migrate(version: string): Promise - }[] = [ - { - version: '1.0.1', - async migrate(version) { - const config: any | void = await storageHelper.get([ - 'configVersion', - 'sideBarWidth', - 'shortcut', - 'access_token', - 'compressSingletonFolder', - 'copyFileButton', - 'copySnippetButton', - 'intelligentToggle', - 'icons', - ]) - if (config && (!('configVersion' in config) || config.configVersion < version)) { - await storageHelper.set({ platform_GitHub: config, configVersion: version }) - } - }, - }, - { - version: '1.3.4', - async migrate(version) { - const config: any | void = await storageHelper.get & Storage>([ - 'configVersion', - 'platform_undefined', // this was a mistake :( - 'platform_GitHub', - 'platform_github.com', - ]) - if ( - config && - 'configVersion' in config && - config.configVersion < version && - (config.platform_GitHub || config.platform_undefined) && - !config['platform_github.com'] - ) { - await storageHelper.set({ - ['platform_github.com']: config.platform_GitHub || config.platform_undefined, - configVersion: version, - }) - } - }, - }, - { - version: '2.6.0', - async migrate(version) { - type LegacySiteConfig = { - access_token?: string - } - type MigratedSiteConfig = { - accessToken?: string - } - - const config = await storageHelper.get & Storage>() - if (config && config.configVersion < version) { - const { configVersion, ...restConfig } = config - for (const key of Object.keys(restConfig)) { - if ( - typeof restConfig[key] === 'object' && - restConfig[key] && - 'access_token' in restConfig[key] - ) { - const config: LegacySiteConfig = restConfig[key] - const { access_token: accessToken, ...legacy } = config - const migrated: MigratedSiteConfig = { - ...legacy, - accessToken, - } - await storageHelper.set({ - [key]: migrated, - }) - } - } - await storageHelper.set({ - configVersion: version, - }) - } - }, - }, - ] - - for (const { version, migrate } of migrations) { - await migrate(version) - } -} - -// do NOT use platform name -const platformStorageKey = `platform_` + window.location.host.toLowerCase() -const prepareConfig = new Promise(async resolve => { - await migrateConfig() - resolve() -}) - -export async function get(): Promise { - await prepareConfig - const config = await storageHelper.get>([platformStorageKey]) - return applyDefaultConfigs(config?.[platformStorageKey] || {}) -} - -export async function set(config: Config) { - return await storageHelper.set({ [platformStorageKey]: config }) -} diff --git a/src/utils/storageHelper.ts b/src/utils/storageHelper.ts index 455907a..e3dc40a 100644 --- a/src/utils/storageHelper.ts +++ b/src/utils/storageHelper.ts @@ -1,6 +1,15 @@ const localStorage = browser.storage.local -export async function get< +export type Storage = { + // save root level `configVersion` for easier future migrating + [key in EnumString<'configVersion'>]: string + + // separate different platform configs to simplify interactions with browser storage API + // e.g. + // ['platform_github.com']?: Config +} + +async function get< T extends { [key: string]: any } @@ -10,8 +19,10 @@ export async function get< } catch (err) {} } -export function set(value: any): Promise | void { +function set(value: any): Promise | void { try { return localStorage.set(value) } catch (err) {} } + +export const storageHelper = { get, set }