Add versioned settings storage with migration support

main
Warinyourself 3 weeks ago
parent 99058f76da
commit ebe15543d8

@ -5,6 +5,7 @@ import { usePageStore } from '@/store/page'
import { useQuerySync } from '@/composables/useQuerySync'
import { useLightdm, initLightdm } from '@/composables/useLightdm'
import { initSystemInfo } from '@/composables/useSystemInfo'
import { useSettingsStorage } from '@/composables/useSettingsStorage'
import { focusInputPassword, setCSSVariable } from '@/utils/helper'
import { hotkeys, toMagicKeyCombo } from '@/utils/hotkeys'
import { initTimer } from '@/utils/time'
@ -15,6 +16,7 @@ export default defineComponent({
setup() {
const appStore = useAppStore()
const pageStore = usePageStore()
const storage = useSettingsStorage()
const keys = useMagicKeys()
const initZoom = () => {
@ -63,7 +65,7 @@ export default defineComponent({
watch(
() => appStore.getMainSettings,
useDebounceFn(() => appStore.syncSettingsWithCache(), 100),
useDebounceFn((settings) => storage.save(settings), 100),
{ deep: true }
)

@ -1,6 +1,7 @@
import { defineComponent } from 'vue'
import { useI18n } from 'vue-i18n'
import { useAppStore } from '@/store/app'
import { useSettingsStorage } from '@/composables/useSettingsStorage'
import { useRouter, useRoute } from 'vue-router'
import AppButton from '@/components/app/AppButton'
import SettingsUsers from './SettingsUsers'
@ -16,8 +17,10 @@ export default defineComponent({
const router = useRouter()
const route = useRoute()
const storage = useSettingsStorage()
const resetSettings = () => {
localStorage.clear()
storage.clear()
appStore.setUpSettings()
if (Object.keys(route.query).length) {
router.replace({})

@ -0,0 +1,61 @@
import type { AppSettings } from '@/models/app'
const STORAGE_KEY = 'settings'
// Bump this when AppSettings schema changes and add a migration below.
const CURRENT_VERSION = 1
interface StoredSettings {
version: number
data: AppSettings
}
// Each entry migrates data from index N to N+1.
// Add a new function here whenever CURRENT_VERSION is incremented.
const migrations: Array<(data: any) => any> = [
// v0 → v1: wrap legacy flat object into versioned format (no field changes needed)
(data) => data,
]
function migrate(data: any, fromVersion: number): AppSettings {
let result = data
for (let v = fromVersion; v < CURRENT_VERSION; v++) {
result = migrations[v]!(result)
}
return result as AppSettings
}
export function useSettingsStorage() {
function load(): AppSettings | null {
try {
const raw = localStorage.getItem(STORAGE_KEY)
if (!raw) return null
const parsed = JSON.parse(raw)
// Legacy unversioned data written before versioning was introduced
if (!('version' in parsed)) {
return migrate(parsed, 0)
}
const stored = parsed as StoredSettings
if (stored.version === CURRENT_VERSION) return stored.data
// Run outstanding migrations
return migrate(stored.data ?? stored, stored.version)
} catch {
return null
}
}
function save(settings: AppSettings): void {
const stored: StoredSettings = { version: CURRENT_VERSION, data: settings }
localStorage.setItem(STORAGE_KEY, JSON.stringify(stored))
}
function clear(): void {
localStorage.removeItem(STORAGE_KEY)
}
return { load, save, clear }
}

@ -5,6 +5,7 @@ import type { AppSettings } from '@/models/app'
import { useThemeStore } from '@/store/theme'
import { useLightdm } from '@/composables/useLightdm'
import { useSettingsStorage } from '@/composables/useSettingsStorage'
import { version as appVersion } from '../../package.json'
export const useAppStore = defineStore('app', () => {
@ -54,29 +55,24 @@ export const useAppStore = defineStore('app', () => {
localStorage.setItem(key, value)
}
function syncSettingsWithCache() {
localStorage.setItem('settings', JSON.stringify(getMainSettings.value))
}
const storage = useSettingsStorage()
function setUpSettings() {
try {
const settings: AppSettings = JSON.parse(localStorage.getItem('settings') || '{}')
const settings = storage.load()
if (!settings) return
if (settings.themes) themeStore.syncThemeWithStore(settings)
if (settings.themes) themeStore.syncThemeWithStore(settings)
const validDesktop = window.lightdm?.sessions.find(({ key }) => key === settings.desktop)?.key
session.desktop.value = validDesktop || window.lightdm?.sessions[0]?.key || 'openbox'
const validDesktop = window.lightdm?.sessions.find(({ key }) => key === settings.desktop)?.key
session.desktop.value = validDesktop || window.lightdm?.sessions[0]?.key || 'openbox'
const validUser = window.lightdm?.users.find(({ username }) => username === settings.username)?.username
session.username.value = validUser || window.lightdm?.users[0]?.username || ''
const validUser = window.lightdm?.users.find(({ username }) => username === settings.username)?.username
session.username.value = validUser || window.lightdm?.users[0]?.username || ''
zoom.value = settings.zoom || 1
hotkeysEnabled.value = settings.hotkeysEnabled ?? false
showTime.value = settings.showTime ?? true
timeFormat.value = settings.timeFormat ?? 'short'
} catch {
setUpSettings()
}
zoom.value = settings.zoom || 1
hotkeysEnabled.value = settings.hotkeysEnabled ?? false
showTime.value = settings.showTime ?? true
timeFormat.value = settings.timeFormat ?? 'short'
}
return {
@ -93,7 +89,6 @@ export const useAppStore = defineStore('app', () => {
getMainSettings,
changeBodyClass,
saveStateApp,
syncSettingsWithCache,
setUpSettings,
}
})

Loading…
Cancel
Save