From 7528a72b2eaec79c70a6f2a8a4c306af22c367c3 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Mon, 16 Mar 2026 09:50:37 +0200 Subject: [PATCH 01/10] fix config/highlight not working upon login --- src/stores/sync_config.js | 10 +++++----- src/stores/user_highlight.js | 6 ++++-- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/stores/sync_config.js b/src/stores/sync_config.js index e43356e8e..27cd53a59 100644 --- a/src/stores/sync_config.js +++ b/src/stores/sync_config.js @@ -25,7 +25,7 @@ import { defaultState as configDefaultState } from 'src/modules/default_config_s import { defaultConfigSync } from 'src/modules/old_default_config_state.js' 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('2026-03-16') // date of writing this, basically export const COMMAND_TRIM_FLAGS = 1000 export const COMMAND_TRIM_FLAGS_AND_RESET = 1001 @@ -615,14 +615,14 @@ export const useSyncConfigStore = defineStore('sync_config', { let dirty = false console.debug('Migrating from old config') - const vuexState = await storage.getItem('vuex-lz') - const { config } = vuexState + const vuexState = await storage.getItem('vuex-lz') ?? {} + vuexState.config = vuexState.config ?? {} - const migratedEntries = new Set(config._syncMigration ?? []) + const migratedEntries = new Set(vuexState.config._syncMigration ?? []) console.debug(`Already migrated Values: ${[...migratedEntries].join()}`) Object.entries(defaultConfigSync).forEach(([key, value]) => { - const oldValue = config[key] + const oldValue = vuexState.config[key] const defaultValue = value const present = oldValue !== undefined diff --git a/src/stores/user_highlight.js b/src/stores/user_highlight.js index c8868921a..6a3badd01 100644 --- a/src/stores/user_highlight.js +++ b/src/stores/user_highlight.js @@ -278,8 +278,10 @@ export const useUserHighlightStore = defineStore('user_highlight', { const userNew = userData.created_at > NEW_USER_DATE let dirty = false - const vuexState = await storage.getItem('vuex-lz') - const { highlight } = vuexState.config + const vuexState = await storage.getItem('vuex-lz') ?? {} + vuexState.config = vuexState.config ?? {} + const highlight = vuexState.config.highlight ?? {} + Object.entries(highlight).forEach(([user, value]) => { if ((highlight[user]._migrated || 0) < 1) { dirty = true From 10b4259de6c8b06932d87a30ede6c7da94194638 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Mon, 16 Mar 2026 09:50:56 +0200 Subject: [PATCH 02/10] don't persist old config --- src/main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.js b/src/main.js index a4269b4a7..ceb8c0878 100644 --- a/src/main.js +++ b/src/main.js @@ -41,7 +41,7 @@ const i18n = createI18n({ messages.setLanguage(i18n.global, currentLocale) const persistedStateOptions = { - paths: ['syncConfig.cache', 'config', 'users.lastLoginName', 'oauth'], + paths: ['users.lastLoginName', 'oauth'], } ;(async () => { From 6a8abf1b325af33f55933b9b15a8e97bebca2e38 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Mon, 16 Mar 2026 14:42:08 +0200 Subject: [PATCH 03/10] more local-only stuff --- src/modules/default_config_state.js | 6 +++--- src/modules/old_default_config_state.js | 6 +++--- src/stores/sync_config.js | 12 ++++++++---- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/modules/default_config_state.js b/src/modules/default_config_state.js index fbfaf08a3..bc2465e70 100644 --- a/src/modules/default_config_state.js +++ b/src/modules/default_config_state.js @@ -49,8 +49,6 @@ export const instanceDefaultConfig = { 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 @@ -121,7 +119,6 @@ export const instanceDefaultConfig = { modalMobileCenter: false, playVideosInModal: false, - useOneClickNsfw: false, useContainFit: true, disableStickyHeaders: false, showScrollbars: false, @@ -165,6 +162,9 @@ export const instanceDefaultConfig = { export const defaultConfigLocal = { hideAttachments: false, hideAttachmentsInConv: false, + hideNsfw: true, + useOneClickNsfw: false, + preloadImage: true, postContentType: 'text/plain', sidebarRight: false, sidebarColumnWidth: '25rem', diff --git a/src/modules/old_default_config_state.js b/src/modules/old_default_config_state.js index e53cafe29..6e0e730de 100644 --- a/src/modules/old_default_config_state.js +++ b/src/modules/old_default_config_state.js @@ -18,8 +18,6 @@ export const defaultConfigSync = { 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 @@ -93,7 +91,6 @@ export const defaultConfigSync = { modalMobileCenter: false, playVideosInModal: false, - useOneClickNsfw: false, useContainFit: true, disableStickyHeaders: false, showScrollbars: false, @@ -169,6 +166,9 @@ export const defaultConfigSync = { export const defaultConfigLocal = { hideAttachments: false, hideAttachmentsInConv: false, + hideNsfw: true, + useOneClickNsfw: false, + preloadImage: true, sidebarColumnWidth: '25rem', contentColumnWidth: '45rem', notifsColumnWidth: '25rem', diff --git a/src/stores/sync_config.js b/src/stores/sync_config.js index 27cd53a59..51327c389 100644 --- a/src/stores/sync_config.js +++ b/src/stores/sync_config.js @@ -21,7 +21,7 @@ import { useInstanceStore } from 'src/stores/instance.js' import { useLocalConfigStore } from 'src/stores/local_config.js' import { storage } from 'src/lib/storage.js' -import { defaultState as configDefaultState } from 'src/modules/default_config_state.js' +import { defaultState as configDefaultState, makeUndefined, defaultConfigLocal } from 'src/modules/default_config_state.js' import { defaultConfigSync } from 'src/modules/old_default_config_state.js' export const VERSION = 2 @@ -31,6 +31,7 @@ export const COMMAND_TRIM_FLAGS = 1000 export const COMMAND_TRIM_FLAGS_AND_RESET = 1001 export const COMMAND_WIPE_JOURNAL = 1010 export const COMMAND_WIPE_JOURNAL_AND_STORAGE = 1011 +const LOCAL_ONLY_KEYS = new Set(Object.keys(defaultConfigLocal)) export const defaultState = { // do we need to update data on server? @@ -49,7 +50,7 @@ export const defaultState = { dontShowUpdateNotifs: false, collapseNav: false, muteFilters: {}, - ...configDefaultState, + ...makeUndefined(configDefaultState), }, collections: { pinnedStatusActions: ['reply', 'retweet', 'favorite', 'emoji'], @@ -636,6 +637,7 @@ export const useSyncConfigStore = defineStore('sync_config', { needUpload = true } }) + vuexState.config._syncMigration = [...migratedEntries] storage.setItem('vuex-lz', vuexState) @@ -716,9 +718,11 @@ export const useSyncConfigStore = defineStore('sync_config', { const localPrefs = useLocalConfigStore().prefsStorage const tempPrefs = useLocalConfigStore().tempStorage const result = Object.fromEntries( - Object.entries(state.prefsStorage.simple).map(([k, v]) => [ + Object.entries(state.prefsStorage.simple).map(([k, value]) => [ k, - tempPrefs[k] ?? localPrefs[k] ?? v ?? instancePrefs[k], + LOCAL_ONLY_KEYS.has(k) + ? tempPrefs[k] ?? localPrefs[k] ?? instancePrefs[k] + : tempPrefs[k] ?? localPrefs[k] ?? value ?? instancePrefs[k], ]), ) return result From 18b10ea0427818e33f9bd6908745e93d0d8fdcae Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Mon, 16 Mar 2026 15:13:48 +0200 Subject: [PATCH 04/10] fix not defaulting to hardcoded defaults --- src/components/font_control/font_control.js | 9 +------- src/modules/default_config_state.js | 18 +++++----------- src/modules/old_default_config_state.js | 2 -- src/stores/local_config.js | 2 +- src/stores/sync_config.js | 24 +++++++++++++++------ src/stores/user_highlight.js | 2 +- 6 files changed, 26 insertions(+), 31 deletions(-) diff --git a/src/components/font_control/font_control.js b/src/components/font_control/font_control.js index d1f3390cc..d7c5aa225 100644 --- a/src/components/font_control/font_control.js +++ b/src/components/font_control/font_control.js @@ -21,14 +21,7 @@ export default { Popover, LocalSettingIndicator, }, - props: [ - 'name', - 'label', - 'modelValue', - 'fallback', - 'options', - 'no-inherit', - ], + props: ['name', 'label', 'modelValue', 'fallback', 'options', 'no-inherit'], mounted() { useInterfaceStore().queryLocalFonts() }, diff --git a/src/modules/default_config_state.js b/src/modules/default_config_state.js index bc2465e70..a391e9b21 100644 --- a/src/modules/default_config_state.js +++ b/src/modules/default_config_state.js @@ -191,9 +191,12 @@ export const makeUndefined = (c) => export const defaultState = { // Set these to undefined so it does not interfere with default settings check ...makeUndefined(instanceDefaultConfig), + ...makeUndefined(defaultConfigLocal), + // If there are any configurations that does not make sense to + // have instance-wide default, put it here and explain why. - // Special processing - // Theme stuff + // # Special processing + // ## Theme stuff theme: undefined, // Very old theme store, stores preset name, still in use // V1 @@ -220,15 +223,4 @@ export const defaultState = { monospace: undefined, }, }, - - // Special handling: These fields are not of a primitive type, and - // might cause problems with current code because it specifically checks - // them in state.config (not getters.mergedConfig). - - // Specifically, muteWords is now deprecated in favour of a server-side configuration. - muteWords: [], - highlight: {}, - - // If there are any configurations that does not make sense to - // have instance-wide default, put it here and explain why. } diff --git a/src/modules/old_default_config_state.js b/src/modules/old_default_config_state.js index 6e0e730de..dc15e1c24 100644 --- a/src/modules/old_default_config_state.js +++ b/src/modules/old_default_config_state.js @@ -182,6 +182,4 @@ export const defaultConfigLocal = { mentionLinkDisplay: 'short', imageCompression: true, alwaysUseJpeg: false, - imageCompression: true, - alwaysUseJpeg: false, } diff --git a/src/stores/local_config.js b/src/stores/local_config.js index 117be393d..73ea1d7d4 100644 --- a/src/stores/local_config.js +++ b/src/stores/local_config.js @@ -32,7 +32,7 @@ export const useLocalConfigStore = defineStore('local_config', { unset({ path, value }) { set(this.prefsStorage, path, undefined) }, - clearSyncConfig() { + clearLocalConfig() { const blankState = { ...cloneDeep(defaultState) } Object.keys(this).forEach((k) => { this.prefsStorage[k] = blankState[k] diff --git a/src/stores/sync_config.js b/src/stores/sync_config.js index 51327c389..b740e1bec 100644 --- a/src/stores/sync_config.js +++ b/src/stores/sync_config.js @@ -21,7 +21,11 @@ import { useInstanceStore } from 'src/stores/instance.js' import { useLocalConfigStore } from 'src/stores/local_config.js' import { storage } from 'src/lib/storage.js' -import { defaultState as configDefaultState, makeUndefined, defaultConfigLocal } from 'src/modules/default_config_state.js' +import { + defaultState as configDefaultState, + defaultConfigLocal, + instanceDefaultConfig, +} from 'src/modules/default_config_state.js' import { defaultConfigSync } from 'src/modules/old_default_config_state.js' export const VERSION = 2 @@ -50,7 +54,8 @@ export const defaultState = { dontShowUpdateNotifs: false, collapseNav: false, muteFilters: {}, - ...makeUndefined(configDefaultState), + + ...configDefaultState, }, collections: { pinnedStatusActions: ['reply', 'retweet', 'favorite', 'emoji'], @@ -616,7 +621,7 @@ export const useSyncConfigStore = defineStore('sync_config', { let dirty = false console.debug('Migrating from old config') - const vuexState = await storage.getItem('vuex-lz') ?? {} + const vuexState = (await storage.getItem('vuex-lz')) ?? {} vuexState.config = vuexState.config ?? {} const migratedEntries = new Set(vuexState.config._syncMigration ?? []) @@ -631,7 +636,7 @@ export const useSyncConfigStore = defineStore('sync_config', { const different = !isEqual(oldValue, defaultValue) if (present && !migrated && different) { - console.debug(`Migrating config ${key}: ${oldValue}`,) + console.debug(`Migrating config ${key}: ${oldValue}`) this.setPreference({ path: `simple.${key}`, oldValue }) migratedEntries.add(key) needUpload = true @@ -721,8 +726,15 @@ export const useSyncConfigStore = defineStore('sync_config', { Object.entries(state.prefsStorage.simple).map(([k, value]) => [ k, LOCAL_ONLY_KEYS.has(k) - ? tempPrefs[k] ?? localPrefs[k] ?? instancePrefs[k] - : tempPrefs[k] ?? localPrefs[k] ?? value ?? instancePrefs[k], + ? (tempPrefs[k] ?? + localPrefs[k] ?? + instancePrefs[k] ?? + defaultConfigLocal[k]) + : (tempPrefs[k] ?? + localPrefs[k] ?? + value ?? + instancePrefs[k] ?? + instanceDefaultConfig[k]), ]), ) return result diff --git a/src/stores/user_highlight.js b/src/stores/user_highlight.js index 6a3badd01..ae2bd4d4c 100644 --- a/src/stores/user_highlight.js +++ b/src/stores/user_highlight.js @@ -278,7 +278,7 @@ export const useUserHighlightStore = defineStore('user_highlight', { const userNew = userData.created_at > NEW_USER_DATE let dirty = false - const vuexState = await storage.getItem('vuex-lz') ?? {} + const vuexState = (await storage.getItem('vuex-lz')) ?? {} vuexState.config = vuexState.config ?? {} const highlight = vuexState.config.highlight ?? {} From 1fb7b6b48b702af0f15a03ed36f82598e2aa2731 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Mon, 16 Mar 2026 15:16:50 +0200 Subject: [PATCH 05/10] fix mute filters being broken --- src/components/settings_modal/tabs/filtering_tab.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/settings_modal/tabs/filtering_tab.js b/src/components/settings_modal/tabs/filtering_tab.js index facc6073f..64710d745 100644 --- a/src/components/settings_modal/tabs/filtering_tab.js +++ b/src/components/settings_modal/tabs/filtering_tab.js @@ -151,7 +151,7 @@ const FilteringTab = { methods: { ...mapActions(useSyncConfigStore, [ 'setPreference', - 'setPrefAndSave', + 'setSimplePrefAndSave', 'unsetPreference', 'unsetPrefAndSave', 'pushSyncConfig', From 392b595dc9d4203fa361896e309dfb7520df1594 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Mon, 16 Mar 2026 15:21:37 +0200 Subject: [PATCH 06/10] more locals --- src/components/settings_modal/tabs/clutter_tab.vue | 4 +--- src/components/settings_modal/tabs/posts_tab.vue | 8 +++++++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/components/settings_modal/tabs/clutter_tab.vue b/src/components/settings_modal/tabs/clutter_tab.vue index 8ae416ff8..533cd85c6 100644 --- a/src/components/settings_modal/tabs/clutter_tab.vue +++ b/src/components/settings_modal/tabs/clutter_tab.vue @@ -83,9 +83,7 @@
  • - + {{ $t('settings.hide_shoutbox') }}
  • diff --git a/src/components/settings_modal/tabs/posts_tab.vue b/src/components/settings_modal/tabs/posts_tab.vue index d14475fc3..444f96392 100644 --- a/src/components/settings_modal/tabs/posts_tab.vue +++ b/src/components/settings_modal/tabs/posts_tab.vue @@ -101,6 +101,7 @@ {{ $t('settings.mention_link_display') }} @@ -171,7 +172,10 @@
  • - + {{ $t('settings.nsfw_clickthrough') }}
      @@ -179,6 +183,7 @@ {{ $t('settings.preload_images') }} @@ -188,6 +193,7 @@ {{ $t('settings.use_one_click_nsfw') }} From 650785bb5b9c4631ee92f6006677511ac712ef01 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Mon, 16 Mar 2026 15:40:42 +0200 Subject: [PATCH 07/10] make SW use pinia cache instead of vuex --- src/sw.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sw.js b/src/sw.js index e3225c91d..bfe35d3c5 100644 --- a/src/sw.js +++ b/src/sw.js @@ -34,14 +34,14 @@ function getWindowClients() { } const setSettings = async () => { - const vuexState = await storage.getItem('vuex-lz') - const locale = vuexState.config.interfaceLanguage || 'en' + const piniaState = await storage.getItem('pinia-local-sync_config') + const locale = piniaState.prefsStorage.simple.interfaceLanguage || 'en' i18n.locale = locale const notificationsNativeArray = Object.entries( - vuexState.config.notificationNative, + piniaState.prefsStorage.simple.notificationNative, ) state.webPushAlwaysShowNotifications = - vuexState.config.webPushAlwaysShowNotifications + piniaState.prefsStorage.simple.webPushAlwaysShowNotifications state.allowedNotificationTypes = new Set( notificationsNativeArray From 195e353b3a7da8cb2c37acc73c1ca567bf766cdd Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Mon, 16 Mar 2026 15:41:01 +0200 Subject: [PATCH 08/10] remainder of old config references --- .../settings_modal/helpers/list_setting.js | 4 +- .../settings_modal_user_content.js | 3 +- .../settings_modal/tabs/clutter_tab.js | 49 ------------------- .../settings_modal/tabs/filtering_tab.js | 4 +- 4 files changed, 7 insertions(+), 53 deletions(-) diff --git a/src/components/settings_modal/helpers/list_setting.js b/src/components/settings_modal/helpers/list_setting.js index c1d504cd5..232ea123f 100644 --- a/src/components/settings_modal/helpers/list_setting.js +++ b/src/components/settings_modal/helpers/list_setting.js @@ -1,6 +1,8 @@ import Checkbox from 'src/components/checkbox/checkbox.vue' import Setting from './setting.js' +import { useSyncConfigStore } from 'src/stores/sync_config.js' + export default { ...Setting, data() { @@ -43,7 +45,7 @@ export default { if (this.forceNew) return true if (!this.allowNew) return false - const isExpert = this.$store.state.config.expertLevel > 0 + const isExpert = useSyncConfigStore().mergedConfig.expertLevel > 0 const hasBuiltins = this.builtinEntries.length > 0 if (hasBuiltins) { diff --git a/src/components/settings_modal/settings_modal_user_content.js b/src/components/settings_modal/settings_modal_user_content.js index ddee812ca..6c33b4fa6 100644 --- a/src/components/settings_modal/settings_modal_user_content.js +++ b/src/components/settings_modal/settings_modal_user_content.js @@ -16,6 +16,7 @@ import SecurityTab from './tabs/security_tab/security_tab.vue' import StyleTab from './tabs/style_tab/style_tab.vue' import { useInterfaceStore } from 'src/stores/interface.js' +import { useSyncConfigStore } from 'src/stores/sync_config.js' import { library } from '@fortawesome/fontawesome-svg-core' import { @@ -83,7 +84,7 @@ const SettingsModalContent = { return useInterfaceStore().settingsModalState === 'visible' }, expertLevel() { - return this.$store.state.config.expertLevel + return useSyncConfigStore().mergedConfig.expertLevel }, }, data() { diff --git a/src/components/settings_modal/tabs/clutter_tab.js b/src/components/settings_modal/tabs/clutter_tab.js index 510425e2d..85749ab3f 100644 --- a/src/components/settings_modal/tabs/clutter_tab.js +++ b/src/components/settings_modal/tabs/clutter_tab.js @@ -38,55 +38,6 @@ const ClutterTab = { Object.entries(store.prefsStorage.simple.muteFilters), muteFiltersObject: (store) => store.prefsStorage.simple.muteFilters, }), - onMuteDefaultActionLv1: { - get() { - const value = this.$store.state.config.onMuteDefaultAction - if (value === 'ask' || value === 'forever') { - return value - } else { - return 'temporarily' - } - }, - set(value) { - let realValue = value - if (value !== 'ask' && value !== 'forever') { - realValue = '14d' - } - useSyncConfigStore().setSimplePrefAndSave({ - path: 'onMuteDefaultAction', - value: realValue, - }) - }, - }, - onBlockDefaultActionLv1: { - get() { - const value = this.$store.state.config.onBlockDefaultAction - if (value === 'ask' || value === 'forever') { - return value - } else { - return 'temporarily' - } - }, - set(value) { - let realValue = value - if (value !== 'ask' && value !== 'forever') { - realValue = '14d' - } - useSyncConfigStore().setSimplePrefAndSave({ - path: 'onBlockDefaultAction', - value: realValue, - }) - }, - }, - muteFiltersDraft() { - return Object.entries(this.muteFiltersDraftObject) - }, - muteFiltersExpired() { - const now = Date.now() - return Object.entries(this.muteFiltersDraftObject).filter( - ([, { expires }]) => expires != null && expires <= now, - ) - }, }, methods: { ...mapActions(useSyncConfigStore, [ diff --git a/src/components/settings_modal/tabs/filtering_tab.js b/src/components/settings_modal/tabs/filtering_tab.js index 64710d745..3724ea0e7 100644 --- a/src/components/settings_modal/tabs/filtering_tab.js +++ b/src/components/settings_modal/tabs/filtering_tab.js @@ -100,7 +100,7 @@ const FilteringTab = { ...mapState(useInstanceCapabilitiesStore, ['blockExpiration']), onMuteDefaultActionLv1: { get() { - const value = this.$store.state.config.onMuteDefaultAction + const value = useSyncConfigStore().mergedConfig.onMuteDefaultAction if (value === 'ask' || value === 'forever') { return value } else { @@ -120,7 +120,7 @@ const FilteringTab = { }, onBlockDefaultActionLv1: { get() { - const value = this.$store.state.config.onBlockDefaultAction + const value = useSyncConfigStore().mergedConfig.onBlockDefaultAction if (value === 'ask' || value === 'forever') { return value } else { From d881b92f86a38fc8992100bde61e75fe0deae32e Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Mon, 16 Mar 2026 16:56:20 +0200 Subject: [PATCH 09/10] fix import/export --- .../settings_modal/settings_modal.js | 26 ++++++++++++++++--- .../settings_modal/tabs/filtering_tab.js | 8 ++++-- src/i18n/en.json | 1 + src/stores/local_config.js | 2 ++ src/stores/sync_config.js | 16 ++++++++++-- 5 files changed, 46 insertions(+), 7 deletions(-) diff --git a/src/components/settings_modal/settings_modal.js b/src/components/settings_modal/settings_modal.js index 25c508bef..853ef5eb0 100644 --- a/src/components/settings_modal/settings_modal.js +++ b/src/components/settings_modal/settings_modal.js @@ -9,6 +9,7 @@ import PanelLoading from 'src/components/panel_loading/panel_loading.vue' import Popover from '../popover/popover.vue' import { useInterfaceStore } from 'src/stores/interface.js' +import { LOCAL_ONLY_KEYS, useLocalConfigStore } from 'src/stores/local_config.js' import { useSyncConfigStore } from 'src/stores/sync_config.js' import { @@ -137,7 +138,24 @@ const SettingsModal = { }, onImport(data) { if (data) { - this.$store.dispatch('loadSettings', data) + Object.entries(data).forEach(([path, value]) => { + if (LOCAL_ONLY_KEYS.has(path)) { + useLocalConfigStore().set({ path, value }) + } else { + if (path.startsWith('muteFilters')) { + Object.keys(useSyncConfigStore().mergedConfig.muteFilters).forEach((key) => { + useSyncConfigStore().unsetPreference({ path: `simple.${path}.${key}` }) + }) + + Object.entries(value).forEach(([key, filter]) => { + useSyncConfigStore().setPreference({ path: `simple.${path}.${key}`, value: filter }) + }) + } else { + useSyncConfigStore().setPreference({ path: `simple.${path}`, value }) + } + } + }) + useSyncConfigStore().pushSyncConfig() } }, restore() { @@ -150,7 +168,7 @@ const SettingsModal = { this.dataThemeExporter.exportData() }, generateExport(theme = false) { - const { config } = this.$store.state + const config = useSyncConfigStore().mergedConfigWithoutDefaults let sample = config if (!theme) { const ignoreList = new Set([ @@ -159,7 +177,9 @@ const SettingsModal = { 'colors', ]) sample = Object.fromEntries( - Object.entries(sample).filter(([key]) => !ignoreList.has(key)), + Object.entries(sample).filter( + ([key, value]) => !ignoreList.has(key) && value !== undefined, + ), ) } const clone = cloneDeep(sample) diff --git a/src/components/settings_modal/tabs/filtering_tab.js b/src/components/settings_modal/tabs/filtering_tab.js index 3724ea0e7..b2694152e 100644 --- a/src/components/settings_modal/tabs/filtering_tab.js +++ b/src/components/settings_modal/tabs/filtering_tab.js @@ -93,8 +93,6 @@ const FilteringTab = { computed: { ...SharedComputedObject(), ...mapState(useSyncConfigStore, { - muteFilters: (store) => - Object.entries(store.prefsStorage.simple.muteFilters), muteFiltersObject: (store) => store.prefsStorage.simple.muteFilters, }), ...mapState(useInstanceCapabilitiesStore, ['blockExpiration']), @@ -260,6 +258,12 @@ const FilteringTab = { replyVisibility() { this.$store.dispatch('queueFlushAll') }, + muteFiltersObject() { + console.log('UPDATE') + this.muteFiltersDraftObject = cloneDeep( + useSyncConfigStore().prefsStorage.simple.muteFilters, + ) + } }, } diff --git a/src/i18n/en.json b/src/i18n/en.json index 70c099932..0165af240 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -381,6 +381,7 @@ "select_all": "Select all" }, "settings": { + "invalid_settings_imported": "Error importing settings", "add_language": "Add fallback language", "remove_language": "Remove", "primary_language": "Primary language:", diff --git a/src/stores/local_config.js b/src/stores/local_config.js index 73ea1d7d4..3611b559e 100644 --- a/src/stores/local_config.js +++ b/src/stores/local_config.js @@ -6,6 +6,8 @@ import { useInstanceStore } from 'src/stores/instance' import { defaultState as configDefaultState } from 'src/modules/default_config_state' +export const LOCAL_ONLY_KEYS = new Set(Object.keys(configDefaultState)) + export const defaultState = { prefsStorage: { ...configDefaultState, diff --git a/src/stores/sync_config.js b/src/stores/sync_config.js index b740e1bec..996f32979 100644 --- a/src/stores/sync_config.js +++ b/src/stores/sync_config.js @@ -18,7 +18,10 @@ import { toRaw } from 'vue' import { CURRENT_UPDATE_COUNTER } from 'src/components/update_notification/update_notification.js' import { useInstanceStore } from 'src/stores/instance.js' -import { useLocalConfigStore } from 'src/stores/local_config.js' +import { + LOCAL_ONLY_KEYS, + useLocalConfigStore, +} from 'src/stores/local_config.js' import { storage } from 'src/lib/storage.js' import { @@ -35,7 +38,6 @@ export const COMMAND_TRIM_FLAGS = 1000 export const COMMAND_TRIM_FLAGS_AND_RESET = 1001 export const COMMAND_WIPE_JOURNAL = 1010 export const COMMAND_WIPE_JOURNAL_AND_STORAGE = 1011 -const LOCAL_ONLY_KEYS = new Set(Object.keys(defaultConfigLocal)) export const defaultState = { // do we need to update data on server? @@ -739,6 +741,16 @@ export const useSyncConfigStore = defineStore('sync_config', { ) return result }, + mergedConfigWithoutDefaults: (state) => { + const localPrefs = useLocalConfigStore().prefsStorage + const result = Object.fromEntries( + Object.entries(state.prefsStorage.simple).map(([k, value]) => [ + k, + LOCAL_ONLY_KEYS.has(k) ? localPrefs[k] : value, + ]), + ) + return result + }, }, persist: { afterLoad(state) { From 55fdb8687a9ab1fba2432cbf04edf62f89314889 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Mon, 16 Mar 2026 17:11:12 +0200 Subject: [PATCH 10/10] lint --- .../settings_modal/settings_modal.js | 23 +++++++++++++++---- .../settings_modal/tabs/filtering_tab.js | 4 ++-- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/components/settings_modal/settings_modal.js b/src/components/settings_modal/settings_modal.js index 853ef5eb0..a99067f36 100644 --- a/src/components/settings_modal/settings_modal.js +++ b/src/components/settings_modal/settings_modal.js @@ -9,7 +9,10 @@ import PanelLoading from 'src/components/panel_loading/panel_loading.vue' import Popover from '../popover/popover.vue' import { useInterfaceStore } from 'src/stores/interface.js' -import { LOCAL_ONLY_KEYS, useLocalConfigStore } from 'src/stores/local_config.js' +import { + LOCAL_ONLY_KEYS, + useLocalConfigStore, +} from 'src/stores/local_config.js' import { useSyncConfigStore } from 'src/stores/sync_config.js' import { @@ -143,15 +146,25 @@ const SettingsModal = { useLocalConfigStore().set({ path, value }) } else { if (path.startsWith('muteFilters')) { - Object.keys(useSyncConfigStore().mergedConfig.muteFilters).forEach((key) => { - useSyncConfigStore().unsetPreference({ path: `simple.${path}.${key}` }) + Object.keys( + useSyncConfigStore().mergedConfig.muteFilters, + ).forEach((key) => { + useSyncConfigStore().unsetPreference({ + path: `simple.${path}.${key}`, + }) }) Object.entries(value).forEach(([key, filter]) => { - useSyncConfigStore().setPreference({ path: `simple.${path}.${key}`, value: filter }) + useSyncConfigStore().setPreference({ + path: `simple.${path}.${key}`, + value: filter, + }) }) } else { - useSyncConfigStore().setPreference({ path: `simple.${path}`, value }) + useSyncConfigStore().setPreference({ + path: `simple.${path}`, + value, + }) } } }) diff --git a/src/components/settings_modal/tabs/filtering_tab.js b/src/components/settings_modal/tabs/filtering_tab.js index b2694152e..3598de757 100644 --- a/src/components/settings_modal/tabs/filtering_tab.js +++ b/src/components/settings_modal/tabs/filtering_tab.js @@ -258,12 +258,12 @@ const FilteringTab = { replyVisibility() { this.$store.dispatch('queueFlushAll') }, - muteFiltersObject() { + muteFiltersObject() { console.log('UPDATE') this.muteFiltersDraftObject = cloneDeep( useSyncConfigStore().prefsStorage.simple.muteFilters, ) - } + }, }, }