Merge branch 'setttingssync' into shigusegubu-themes3

This commit is contained in:
Henry Jameson 2026-03-15 19:55:02 +02:00
commit 7b517a85bf
21 changed files with 279 additions and 179 deletions

View file

@ -156,7 +156,7 @@ export default {
} }
} }
}, },
shout() { shoutJoined() {
return useShoutStore().joined return useShoutStore().joined
}, },
isChats() { isChats() {

View file

@ -60,8 +60,8 @@
/> />
</div> </div>
<MediaModal /> <MediaModal />
<shout-panel <ShoutPanel
v-if="currentUser && shout && !hideShoutbox" v-if="currentUser && !hideShoutbox && shoutJoined"
:floating="true" :floating="true"
class="floating-shout mobile-hidden" class="floating-shout mobile-hidden"
:class="{ '-left': shoutboxPosition }" :class="{ '-left': shoutboxPosition }"

View file

@ -86,7 +86,7 @@ export default {
}, },
// Readable label // Readable label
label: { label: {
required: true, required: false,
type: String, type: String,
}, },
// use unstyled, uh, style // use unstyled, uh, style

View file

@ -28,7 +28,6 @@ export default {
'fallback', 'fallback',
'options', 'options',
'no-inherit', 'no-inherit',
'isLocal',
], ],
mounted() { mounted() {
useInterfaceStore().queryLocalFonts() useInterfaceStore().queryLocalFonts()

View file

@ -8,7 +8,7 @@
:model-value="present" :model-value="present"
@change="$emit('update:modelValue', typeof modelValue === 'undefined' ? fallback : undefined)" @change="$emit('update:modelValue', typeof modelValue === 'undefined' ? fallback : undefined)"
> >
<LocalSettingIndicator :is-local="isLocal" /> <LocalSettingIndicator />
{{ ' ' }} {{ ' ' }}
<i18n-t <i18n-t
scope="global" scope="global"

View file

@ -51,6 +51,7 @@
<li> <li>
<ColorSetting <ColorSetting
hide-draft-buttons hide-draft-buttons
label=""
path=":pleroma.:manifest.:theme_color" path=":pleroma.:manifest.:theme_color"
/> />
</li> </li>
@ -99,7 +100,7 @@
override-backend-description override-backend-description
override-backend-description-label override-backend-description-label
override-available-options override-available-options
:options="limitLocalContentOptions" :options="[...limitLocalContentOptions]"
path=":pleroma.:instance.:limit_to_local_content" path=":pleroma.:instance.:limit_to_local_content"
/> />
</li> </li>

View file

@ -29,7 +29,7 @@ export default {
// The "server" part is primarily for local dev, but could be useful for alt-domain or multiuser usage. // The "server" part is primarily for local dev, but could be useful for alt-domain or multiuser usage.
const url = path.includes('://') ? path : useInstanceStore().server + path const url = path.includes('://') ? path : useInstanceStore().server + path
return { return {
mimetype: fileTypeExt(url), type: fileTypeExt(url),
url, url,
} }
}, },

View file

@ -20,6 +20,7 @@
{{ ' ' }} {{ ' ' }}
<ColorInput <ColorInput
:id="path" :id="path"
:name="path"
class="setting-control color-setting-input" class="setting-control color-setting-input"
:class="{ disabled: shouldBeDisabled }" :class="{ disabled: shouldBeDisabled }"
:disabled="shouldBeDisabled" :disabled="shouldBeDisabled"

View file

@ -9,6 +9,13 @@
class="setting-label" class="setting-label"
:class="{ 'faint': shouldBeDisabled }" :class="{ 'faint': shouldBeDisabled }"
> >
<ModifiedIndicator
:changed="isChanged"
:onclick="reset"
/>
<LocalSettingIndicator :is-local="isLocalSetting" />
{{ ' ' }}
<DraftButtons v-if="!hideDraftButtons" />
<template v-if="backendDescriptionLabel"> <template v-if="backendDescriptionLabel">
{{ backendDescriptionLabel + ' ' }} {{ backendDescriptionLabel + ' ' }}
</template> </template>
@ -29,13 +36,6 @@
:value="realDraftMode ? draft :state" :value="realDraftMode ? draft :state"
@change="update" @change="update"
> >
{{ ' ' }}
<ModifiedIndicator
:changed="isChanged"
:onclick="reset"
/>
<LocalSettingIndicator :is-local="isLocalSetting" />
<DraftButtons v-if="!hideDraftButtons" />
<p <p
v-if="backendDescriptionDescription" v-if="backendDescriptionDescription"
class="setting-description" class="setting-description"

View file

@ -33,14 +33,14 @@ export default {
const path = e[':src'] const path = e[':src']
if (!path) { if (!path) {
return { return {
mimetype: '', type: '',
url: '', url: '',
} }
} }
const url = path.includes('://') ? path : useInstanceStore().server + path const url = path.includes('://') ? path : useInstanceStore().server + path
return { return {
mimetype: fileTypeExt(url), type: fileTypeExt(url),
url, url,
} }
}, },

View file

@ -50,7 +50,7 @@
<div class="src-field"> <div class="src-field">
<Attachment <Attachment
class="src-attachment" class="src-attachment"
:compact="compact" :compact="true"
:attachment="attachment(item)" :attachment="attachment(item)"
size="small" size="small"
hide-description hide-description
@ -70,7 +70,7 @@
class="src-upload media-upload-icon" class="src-upload media-upload-icon"
:class="{ disabled: shouldBeDisabled }" :class="{ disabled: shouldBeDisabled }"
normal-button normal-button
:accept-types="acceptTypes" accept-types="image"
@uploaded="event => setMediaFile({ event, index })" @uploaded="event => setMediaFile({ event, index })"
/> />
</div> </div>

View file

@ -62,12 +62,18 @@
</IntegerSetting> </IntegerSetting>
</li> </li>
<li> <li>
<BooleanSetting path="hideAttachments"> <BooleanSetting
:local="true"
path="hideAttachments"
>
{{ $t('settings.hide_attachments_in_tl') }} {{ $t('settings.hide_attachments_in_tl') }}
</BooleanSetting> </BooleanSetting>
</li> </li>
<li> <li>
<BooleanSetting path="hideAttachmentsInConv"> <BooleanSetting
:local="true"
path="hideAttachmentsInConv"
>
{{ $t('settings.hide_attachments_in_convo') }} {{ $t('settings.hide_attachments_in_convo') }}
</BooleanSetting> </BooleanSetting>
</li> </li>

View file

@ -12,6 +12,7 @@ import SharedComputedObject from '../helpers/shared_computed_object.js'
import UnitSetting from '../helpers/unit_setting.vue' import UnitSetting from '../helpers/unit_setting.vue'
import { useInstanceStore } from 'src/stores/instance.js' import { useInstanceStore } from 'src/stores/instance.js'
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
import { useSyncConfigStore } from 'src/stores/sync_config.js' import { useSyncConfigStore } from 'src/stores/sync_config.js'
import localeService from 'src/services/locale/locale.service.js' import localeService from 'src/services/locale/locale.service.js'
@ -104,7 +105,7 @@ const ComposingTab = {
}, },
computed: { computed: {
postFormats() { postFormats() {
return useInstanceStore().postFormats || [] return useInstanceCapabilitiesStore().postFormats
}, },
postContentOptions() { postContentOptions() {
return this.postFormats.map((format) => ({ return this.postFormats.map((format) => ({

View file

@ -29,6 +29,7 @@
id="postContentType" id="postContentType"
path="postContentType" path="postContentType"
:options="postContentOptions" :options="postContentOptions"
:local="true"
> >
{{ $t('settings.default_post_status_content_type') }} {{ $t('settings.default_post_status_content_type') }}
</ChoiceSetting> </ChoiceSetting>
@ -90,6 +91,7 @@
<li> <li>
<BooleanSetting <BooleanSetting
path="imageCompression" path="imageCompression"
:local="true"
expert="1" expert="1"
> >
{{ $t('settings.image_compression') }} {{ $t('settings.image_compression') }}
@ -98,6 +100,7 @@
<li> <li>
<BooleanSetting <BooleanSetting
path="alwaysUseJpeg" path="alwaysUseJpeg"
:local="true"
expert="1" expert="1"
parent-path="imageCompression" parent-path="imageCompression"
> >

View file

@ -68,7 +68,6 @@
name="ui" name="ui"
:label="$t('settings.style.fonts.components_inline.interface')" :label="$t('settings.style.fonts.components_inline.interface')"
:fallback="{ family: 'sans-serif' }" :fallback="{ family: 'sans-serif' }"
:is-local="true"
no-inherit="1" no-inherit="1"
@update:model-value="v => updateFont('interface', v)" @update:model-value="v => updateFont('interface', v)"
/> />
@ -77,7 +76,6 @@
<FontControl <FontControl
:model-value="theme3hacks.fonts.input" :model-value="theme3hacks.fonts.input"
name="input" name="input"
:is-local="true"
:fallback="{ family: 'inherit' }" :fallback="{ family: 'inherit' }"
:label="$t('settings.style.fonts.components_inline.input')" :label="$t('settings.style.fonts.components_inline.input')"
@update:model-value="v => updateFont('input', v)" @update:model-value="v => updateFont('input', v)"
@ -100,6 +98,7 @@
<FloatSetting <FloatSetting
v-if="user" v-if="user"
path="emojiReactionsScale" path="emojiReactionsScale"
:local="true"
> >
{{ $t('settings.emoji_reactions_scale') }} {{ $t('settings.emoji_reactions_scale') }}
</FloatSetting> </FloatSetting>

View file

@ -40,6 +40,7 @@
<li> <li>
<UnitSetting <UnitSetting
path="themeEditorMinWidth" path="themeEditorMinWidth"
:local="true"
:units="['px', 'rem']" :units="['px', 'rem']"
expert="1" expert="1"
> >
@ -83,12 +84,18 @@
</UnitSetting> </UnitSetting>
</li> </li>
<li> <li>
<BooleanSetting path="sidebarRight"> <BooleanSetting
:local="true"
path="sidebarRight"
>
{{ $t('settings.right_sidebar') }} {{ $t('settings.right_sidebar') }}
</BooleanSetting> </BooleanSetting>
</li> </li>
<li> <li>
<BooleanSetting path="navbarColumnStretch"> <BooleanSetting
:local="true"
path="navbarColumnStretch"
>
{{ $t('settings.navbar_column_stretch') }} {{ $t('settings.navbar_column_stretch') }}
</BooleanSetting> </BooleanSetting>
</li> </li>

View file

@ -37,7 +37,7 @@ const UserAvatar = {
data() { data() {
return { return {
showPlaceholder: false, showPlaceholder: false,
defaultAvatar: `${useInstanceStore().server + useInstanceStore().defaultAvatar}`, defaultAvatar: `${useInstanceStore().server + useInstanceStore().instanceIdentity.defaultAvatar}`,
betterShadow: useInterfaceStore().browserSupport.cssFilter, betterShadow: useInterfaceStore().browserSupport.cssFilter,
} }
}, },

View file

@ -345,7 +345,7 @@ const api = {
// Set up websocket connection // Set up websocket connection
const token = state.wsToken const token = state.wsToken
if ( if (
useInstanceStore().shoutAvailable && useInstanceCapabilitiesStore().shoutAvailable &&
typeof token !== 'undefined' && typeof token !== 'undefined' &&
state.socket === null state.socket === null
) { ) {

View file

@ -45,7 +45,6 @@ export const instanceDefaultConfig = {
muteSensitiveStatuses: false, muteSensitiveStatuses: false,
collapseMessageWithSubject: false, collapseMessageWithSubject: false,
padEmoji: true, padEmoji: true,
hideAttachments: false,
hideAttachmentsInConv: false, hideAttachmentsInConv: false,
hideScrobbles: false, hideScrobbles: false,
hideScrobblesAfter: '2d', hideScrobblesAfter: '2d',
@ -95,12 +94,9 @@ export const instanceDefaultConfig = {
webPushAlwaysShowNotifications: false, webPushAlwaysShowNotifications: false,
interfaceLanguage: browserLocale, interfaceLanguage: browserLocale,
hideScopeNotice: false, hideScopeNotice: false,
useStreamingApi: false,
sidebarRight: false,
scopeCopy: true, scopeCopy: true,
subjectLineBehavior: 'email', subjectLineBehavior: 'email',
alwaysShowSubjectInput: true, alwaysShowSubjectInput: true,
postContentType: 'text/plain',
minimalScopesMode: false, minimalScopesMode: false,
// This hides statuses filtered via a word filter // This hides statuses filtered via a word filter
@ -133,19 +129,8 @@ export const instanceDefaultConfig = {
userPopoverOverlay: false, userPopoverOverlay: false,
userCardLeftJustify: false, userCardLeftJustify: false,
userCardHidePersonalMarks: false, userCardHidePersonalMarks: false,
sidebarColumnWidth: '25rem',
contentColumnWidth: '45rem',
notifsColumnWidth: '25rem',
themeEditorMinWidth: '0rem',
emojiReactionsScale: 0.5,
textSize: '1rem',
emojiSize: '2.2rem',
navbarSize: '3.5rem',
panelHeaderSize: '3.2rem',
forcedRoundness: -1, forcedRoundness: -1,
navbarColumnStretch: false,
greentext: false, greentext: false,
mentionLinkDisplay: 'short',
mentionLinkShowTooltip: true, mentionLinkShowTooltip: true,
mentionLinkShowAvatar: false, mentionLinkShowAvatar: false,
mentionLinkFadeDomain: true, mentionLinkFadeDomain: true,
@ -175,8 +160,27 @@ export const instanceDefaultConfig = {
useAbsoluteTimeFormat: false, useAbsoluteTimeFormat: false,
absoluteTimeFormatMinAge: '0d', absoluteTimeFormatMinAge: '0d',
absoluteTime12h: '24h', absoluteTime12h: '24h',
imageCompression: true, }
export const defaultConfigLocal = {
hideAttachments: false,
hideAttachmentsInConv: false,
postContentType: 'text/plain',
sidebarRight: false,
sidebarColumnWidth: '25rem',
contentColumnWidth: '45rem',
notifsColumnWidth: '25rem',
themeEditorMinWidth: '0rem',
emojiReactionsScale: 0.5,
textSize: '1rem',
emojiSize: '2.2rem',
navbarSize: '3.5rem',
panelHeaderSize: '3.2rem',
navbarColumnStretch: false,
mentionLinkDisplay: 'short',
alwaysUseJpeg: false, alwaysUseJpeg: false,
imageCompression: true,
useStreamingApi: false,
} }
export const makeUndefined = (c) => export const makeUndefined = (c) =>

View file

@ -1,129 +1,187 @@
// this is a snapshot of config keys used prior to sync config. // this is a snapshot of config keys used prior to sync config.
// used to migrate from old config. // used to migrate from old config.
export const defaultStateKeys = [
'expertLevel',
'hideISP',
'hideInstanceWallpaper',
'hideShoutbox',
'hideMutedPosts',
'hideMutedThreads',
'hideWordFilteredPosts',
'muteBotStatuses',
'muteSensitiveStatuses',
'collapseMessageWithSubject',
'padEmoji',
'hideAttachments',
'hideAttachmentsInConv',
'hideScrobbles',
'hideScrobblesAfter',
'maxThumbnails',
'hideNsfw',
'preloadImage',
'loopVideo',
'loopVideoSilentOnly',
'streaming',
'emojiReactionsOnTimeline',
'alwaysShowNewPostButton',
'autohideFloatingPostButton',
'pauseOnUnfocused',
'stopGifs',
'replyVisibility',
'thirdColumnMode',
'notificationVisibility',
'notificationNative',
'webPushNotifications',
'webPushAlwaysShowNotifications',
'interfaceLanguage',
'hideScopeNotice',
'useStreamingApi',
'sidebarRight',
'scopeCopy',
'subjectLineBehavior',
'alwaysShowSubjectInput',
'postContentType',
'minimalScopesMode',
'hideFilteredStatuses',
'modalOnRepeat',
'modalOnUnfollow',
'modalOnBlock',
'modalOnMute',
'modalOnMuteConversation',
'modalOnMuteDomain',
'modalOnDelete',
'modalOnLogout',
'modalOnApproveFollow',
'modalOnDenyFollow',
'modalOnRemoveUserFromFollowers',
'onMuteDefaultAction',
'onBlockDefaultAction',
'modalMobileCenter',
'playVideosInModal',
'useOneClickNsfw',
'useContainFit',
'disableStickyHeaders',
'showScrollbars',
'userPopoverAvatarAction',
'userPopoverOverlay',
'userCardLeftJustify',
'userCardHidePersonalMarks',
'sidebarColumnWidth',
'contentColumnWidth',
'notifsColumnWidth',
'themeEditorMinWidth',
'emojiReactionsScale',
'textSize',
'emojiSize',
'navbarSize',
'panelHeaderSize',
'forcedRoundness',
'navbarColumnStretch',
'greentext',
'mentionLinkDisplay',
'mentionLinkShowTooltip',
'mentionLinkShowAvatar',
'mentionLinkFadeDomain',
'mentionLinkShowYous',
'mentionLinkBoldenYou',
'hidePostStats',
'hideBotIndication',
'hideUserStats',
'virtualScrolling',
'sensitiveByDefault',
'conversationDisplay',
'conversationTreeAdvanced',
'conversationOtherRepliesButton',
'conversationTreeFadeAncestors',
'showExtraNotifications',
'showExtraNotificationsTip',
'showChatsInExtraNotifications',
'showAnnouncementsInExtraNotifications',
'showFollowRequestsInExtraNotifications',
'maxDepthInThread',
'autocompleteSelect',
'closingDrawerMarksAsSeen',
'unseenAtTop',
'ignoreInactionableSeen',
'unsavedPostAction',
'autoSaveDraft',
'useAbsoluteTimeFormat',
'absoluteTimeFormatMinAge',
'absoluteTime12h',
'imageCompression',
'alwaysUseJpeg',
'theme',
'colors', // commented entries are unsynced stuff
export const defaultConfigSync = {
expertLevel: 0, // used to track which settings to show and hide
hideISP: false,
hideInstanceWallpaper: false,
hideShoutbox: false,
// bad name: actually hides posts of muted USERS
hideMutedPosts: false,
hideMutedThreads: true,
hideWordFilteredPosts: false,
muteBotStatuses: false,
muteSensitiveStatuses: false,
collapseMessageWithSubject: false,
padEmoji: true,
hideScrobbles: false,
hideScrobblesAfter: '2d',
maxThumbnails: 16,
hideNsfw: true,
preloadImage: true,
loopVideo: true,
loopVideoSilentOnly: true,
/// This is not the streaming API configuration, but rather an option
/// for automatically loading new posts into the timeline without
/// the user clicking the Show New button.
streaming: false,
emojiReactionsOnTimeline: true,
alwaysShowNewPostButton: false,
autohideFloatingPostButton: false,
pauseOnUnfocused: true,
stopGifs: true,
replyVisibility: 'all',
thirdColumnMode: 'notifications',
notificationVisibility: {
follows: true,
mentions: true,
statuses: true,
likes: true,
repeats: true,
moves: true,
emojiReactions: true,
followRequest: true,
reports: true,
chatMention: true,
polls: true,
},
notificationNative: {
follows: true,
mentions: true,
statuses: true,
likes: false,
repeats: false,
moves: false,
emojiReactions: false,
followRequest: true,
reports: true,
chatMention: true,
polls: true,
},
webPushNotifications: false,
webPushAlwaysShowNotifications: false,
//interfaceLanguage: '',
hideScopeNotice: false,
useStreamingApi: false,
sidebarRight: false,
scopeCopy: true,
subjectLineBehavior: 'email',
alwaysShowSubjectInput: true,
postContentType: 'text/plain',
minimalScopesMode: false,
'customTheme', // This hides statuses filtered via a word filter
'customThemeSource', hideFilteredStatuses: false,
'style', // Confirmations
'styleCustomData', modalOnRepeat: false,
'palette', modalOnUnfollow: false,
'paletteCustomData', modalOnBlock: true,
'themeDebug', modalOnMute: false,
'forceThemeRecompilation', modalOnMuteConversation: false,
'theme3hacks', modalOnMuteDomain: true,
// 'muteWords', // mutes migrated separately modalOnDelete: true,
// 'highlight', // highlight migration is done separately modalOnLogout: true,
] modalOnApproveFollow: false,
modalOnDenyFollow: false,
modalOnRemoveUserFromFollowers: false,
// Expiry confirmations/default actions
onMuteDefaultAction: 'ask',
onBlockDefaultAction: 'ask',
modalMobileCenter: false,
playVideosInModal: false,
useOneClickNsfw: false,
useContainFit: true,
disableStickyHeaders: false,
showScrollbars: false,
userPopoverAvatarAction: 'open',
userPopoverOverlay: false,
userCardLeftJustify: false,
userCardHidePersonalMarks: false,
forcedRoundness: -1,
greentext: false,
mentionLinkShowTooltip: true,
mentionLinkShowAvatar: false,
mentionLinkFadeDomain: true,
mentionLinkShowYous: false,
mentionLinkBoldenYou: true,
hidePostStats: false,
hideBotIndication: false,
hideUserStats: false,
virtualScrolling: true,
sensitiveByDefault: false,
conversationDisplay: 'linear',
conversationTreeAdvanced: false,
conversationOtherRepliesButton: 'below',
conversationTreeFadeAncestors: false,
showExtraNotifications: true,
showExtraNotificationsTip: true,
showChatsInExtraNotifications: true,
showAnnouncementsInExtraNotifications: true,
showFollowRequestsInExtraNotifications: true,
maxDepthInThread: 6,
autocompleteSelect: false,
closingDrawerMarksAsSeen: true,
unseenAtTop: false,
ignoreInactionableSeen: false,
unsavedPostAction: 'confirm',
autoSaveDraft: false,
useAbsoluteTimeFormat: false,
absoluteTimeFormatMinAge: '0d',
absoluteTime12h: '24h',
theme3hacks: {
// Hacks, user overrides that are independent of theme used
underlay: 'none',
fonts: {
interface: undefined,
input: undefined,
post: undefined,
monospace: undefined,
},
},
// Special processing
// Theme stuff
theme: undefined, // Very old theme store, stores preset name, still in use
// V1
colors: {}, // VERY old theme store, just colors of V1, probably not even used anymore
// V2
customTheme: undefined, // "snapshot", previously was used as actual theme store for V2 so it's still used in case of PleromaFE downgrade event.
customThemeSource: undefined, // "source", stores original theme data
// V3
style: null,
styleCustomData: null,
palette: null,
paletteCustomData: null,
themeDebug: false, // debug mode that uses computed backgrounds instead of real ones to debug contrast functions
forceThemeRecompilation: false, // flag that forces recompilation on boot even if cache exists
// Those are handled outside config now
// muteWords: [],
// highlight: {},
}
export const defaultConfigLocal = {
hideAttachments: false,
hideAttachmentsInConv: false,
sidebarColumnWidth: '25rem',
contentColumnWidth: '45rem',
notifsColumnWidth: '25rem',
themeEditorMinWidth: '0rem',
emojiReactionsScale: 0.5,
textSize: '1rem',
emojiSize: '2.2rem',
navbarSize: '3.5rem',
panelHeaderSize: '3.2rem',
navbarColumnStretch: false,
mentionLinkDisplay: 'short',
imageCompression: true,
alwaysUseJpeg: false,
imageCompression: true,
alwaysUseJpeg: false,
}

View file

@ -22,7 +22,7 @@ import { useLocalConfigStore } from 'src/stores/local_config.js'
import { storage } from 'src/lib/storage.js' import { storage } from 'src/lib/storage.js'
import { defaultState as configDefaultState } from 'src/modules/default_config_state.js' import { defaultState as configDefaultState } from 'src/modules/default_config_state.js'
import { defaultStateKeys } from 'src/modules/old_default_config_state.js' import { defaultConfigSync } from 'src/modules/old_default_config_state.js'
export const VERSION = 2 export const VERSION = 2
export const NEW_USER_DATE = new Date('2022-08-04') // date of writing this, basically export const NEW_USER_DATE = new Date('2022-08-04') // date of writing this, basically
@ -38,7 +38,6 @@ export const defaultState = {
// storage of flags - stuff that can only be set and incremented // storage of flags - stuff that can only be set and incremented
flagStorage: { flagStorage: {
updateCounter: 0, // Counter for most recent update notification seen updateCounter: 0, // Counter for most recent update notification seen
configMigration: 0, // Counter for config -> server-side migrations
reset: 0, // special flag that can be used to force-reset all data, debug purposes only reset: 0, // special flag that can be used to force-reset all data, debug purposes only
// special reset codes: // special reset codes:
// 1000: trim keys to those known by currently running FE // 1000: trim keys to those known by currently running FE
@ -417,14 +416,6 @@ export const _doMigrations = async (data, setPreference) => {
console.debug( console.debug(
'Data has older version, seeing if there any migrations that can be applied', 'Data has older version, seeing if there any migrations that can be applied',
) )
if (data._version === 1) {
// Migrate old config to sync config
const vuexState = await storage.getItem('vuex-lz')
defaultStateKeys.forEach((key) => {
setPreference({ path: `simple.${key}`, value: vuexState.config[key] })
})
}
} }
if (data._version > VERSION) { if (data._version > VERSION) {
@ -623,6 +614,31 @@ export const useSyncConfigStore = defineStore('sync_config', {
const flagsTemplate = userNew ? newUserFlags : defaultState.flagStorage const flagsTemplate = userNew ? newUserFlags : defaultState.flagStorage
let dirty = false let dirty = false
console.debug('Migrating from old config')
const vuexState = await storage.getItem('vuex-lz')
const { config } = vuexState
const migratedEntries = new Set(config._syncMigration ?? [])
console.debug(`Already migrated Values: ${[...migratedEntries].join()}`)
Object.entries(defaultConfigSync).forEach(([key, value]) => {
const oldValue = config[key]
const defaultValue = value
const present = oldValue !== undefined
const migrated = migratedEntries.has(key)
const different = !isEqual(oldValue, defaultValue)
if (present && !migrated && different) {
console.debug(`Migrating config ${key}: ${oldValue}`,)
this.setPreference({ path: `simple.${key}`, oldValue })
migratedEntries.add(key)
needUpload = true
}
})
vuexState.config._syncMigration = [...migratedEntries]
storage.setItem('vuex-lz', vuexState)
if (recent === null) { if (recent === null) {
console.debug( console.debug(
`Data is empty, initializing for ${userNew ? 'new' : 'existing'} user`, `Data is empty, initializing for ${userNew ? 'new' : 'existing'} user`,
@ -641,7 +657,12 @@ export const useSyncConfigStore = defineStore('sync_config', {
// discarding timestamps and versions // discarding timestamps and versions
const { _timestamp: _0, _version: _1, ...recentData } = recent const { _timestamp: _0, _version: _1, ...recentData } = recent
const { _timestamp: _2, _version: _3, ...staleData } = stale const { _timestamp: _2, _version: _3, ...staleData } = stale
dirty = !isEqual(recentData, staleData) dirty = !isEqual(
// Something wrong happens if we compare both objects directly
// or with cloneDeep()
JSON.parse(JSON.stringify(recentData)),
JSON.parse(JSON.stringify(staleData)),
)
console.debug(`Data ${dirty ? 'needs' : "doesn't need"} merging`) console.debug(`Data ${dirty ? 'needs' : "doesn't need"} merging`)
} }