mirror of
https://github.com/EnixCoda/Gitako.git
synced 2026-03-11 08:54:44 +00:00
refactor: destruct config helper
This commit is contained in:
parent
31c45781a0
commit
ab82cf783e
12 changed files with 211 additions and 188 deletions
|
|
@ -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<Key extends keyof Config> = {
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -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<ContextShape | null>(null)
|
|||
export function ConfigsContextWrapper(props: React.PropsWithChildren<Props>) {
|
||||
const [configs, setConfigs] = React.useState<Config | null>(null)
|
||||
React.useEffect(() => {
|
||||
configsHelper.get().then(setConfigs)
|
||||
configHelper.get().then(setConfigs)
|
||||
}, [])
|
||||
const onChange = React.useCallback(
|
||||
(updatedConfigs: Partial<Config>) => {
|
||||
const mergedConfigs = { ...configs, ...updatedConfigs } as Config
|
||||
configsHelper.set(mergedConfigs)
|
||||
configHelper.set(mergedConfigs)
|
||||
setConfigs(mergedConfigs)
|
||||
},
|
||||
[configs, setConfigs],
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
||||
|
|
|
|||
81
src/utils/config/helper.ts
Normal file
81
src/utils/config/helper.ts
Normal file
|
|
@ -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<Config>) {
|
||||
return configKeyArray.reduce((applied, key) => {
|
||||
Object.assign(applied, { [key]: key in configs ? configs[key] : defaultConfigs[key] })
|
||||
return applied
|
||||
}, {} as Config)
|
||||
}
|
||||
|
||||
export type VersionedConfig<SiteConfig> = Record<string, SiteConfig> & { configVersion: string }
|
||||
|
||||
// do NOT use platform name
|
||||
const platformStorageKey = `platform_` + window.location.host.toLowerCase()
|
||||
const prepareConfig = new Promise<void>(async resolve => {
|
||||
await migrateConfig()
|
||||
resolve()
|
||||
})
|
||||
|
||||
async function get(): Promise<Config> {
|
||||
await prepareConfig
|
||||
const config = await storageHelper.get<Record<string, Config>>([platformStorageKey])
|
||||
return applyDefaultConfigs(config?.[platformStorageKey] || {})
|
||||
}
|
||||
|
||||
async function set(config: Config) {
|
||||
return await storageHelper.set({ [platformStorageKey]: config })
|
||||
}
|
||||
|
||||
export const configHelper = { get, set }
|
||||
23
src/utils/config/migrations/1.0.1.ts
Normal file
23
src/utils/config/migrations/1.0.1.ts
Normal file
|
|
@ -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<Storage>([
|
||||
'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 })
|
||||
}
|
||||
},
|
||||
}
|
||||
28
src/utils/config/migrations/1.3.4.ts
Normal file
28
src/utils/config/migrations/1.3.4.ts
Normal file
|
|
@ -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<VersionedConfig<Config> & 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,
|
||||
})
|
||||
}
|
||||
},
|
||||
}
|
||||
41
src/utils/config/migrations/2.6.0.ts
Normal file
41
src/utils/config/migrations/2.6.0.ts
Normal file
|
|
@ -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<VersionedConfig<ConfigBeforeMigrate> & 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,
|
||||
})
|
||||
}
|
||||
},
|
||||
}
|
||||
18
src/utils/config/migrations/index.ts
Normal file
18
src/utils/config/migrations/index.ts
Normal file
|
|
@ -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<void>
|
||||
}
|
||||
|
||||
export async function migrateConfig() {
|
||||
const migrations: Migration[] = [v1v0v1, v1v3v4, v2v6v0]
|
||||
|
||||
for (const { version, migrate } of migrations) {
|
||||
await migrate(version)
|
||||
}
|
||||
}
|
||||
|
|
@ -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<Config>) {
|
||||
return configKeyArray.reduce((applied, key) => {
|
||||
Object.assign(applied, { [key]: key in configs ? configs[key] : defaultConfigs[key] })
|
||||
return applied
|
||||
}, {} as Config)
|
||||
}
|
||||
|
||||
type VersionedConfig<SiteConfig> = Record<string, SiteConfig> & { 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<void>
|
||||
}[] = [
|
||||
{
|
||||
version: '1.0.1',
|
||||
async migrate(version) {
|
||||
const config: any | void = await storageHelper.get<Storage>([
|
||||
'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<VersionedConfig<Config> & 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<VersionedConfig<LegacySiteConfig> & 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<void>(async resolve => {
|
||||
await migrateConfig()
|
||||
resolve()
|
||||
})
|
||||
|
||||
export async function get(): Promise<Config> {
|
||||
await prepareConfig
|
||||
const config = await storageHelper.get<Record<string, Config>>([platformStorageKey])
|
||||
return applyDefaultConfigs(config?.[platformStorageKey] || {})
|
||||
}
|
||||
|
||||
export async function set(config: Config) {
|
||||
return await storageHelper.set({ [platformStorageKey]: config })
|
||||
}
|
||||
|
|
@ -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> | void {
|
||||
function set(value: any): Promise<void> | void {
|
||||
try {
|
||||
return localStorage.set(value)
|
||||
} catch (err) {}
|
||||
}
|
||||
|
||||
export const storageHelper = { get, set }
|
||||
|
|
|
|||
Loading…
Reference in a new issue