Merge branch 'setttingssync' into shigusegubu-themes3

This commit is contained in:
Henry Jameson 2026-03-24 15:46:02 +02:00
commit bb0656c505
7 changed files with 522 additions and 163 deletions

View file

@ -1,6 +1,6 @@
import { throttle } from 'lodash' import { throttle } from 'lodash'
import { mapState } from 'pinia' import { mapState } from 'pinia'
import { defineAsyncComponent } from 'vue' import { defineAsyncComponent, toValue } from 'vue'
import DesktopNav from './components/desktop_nav/desktop_nav.vue' import DesktopNav from './components/desktop_nav/desktop_nav.vue'
import EditStatusModal from './components/edit_status_modal/edit_status_modal.vue' import EditStatusModal from './components/edit_status_modal/edit_status_modal.vue'
@ -32,6 +32,9 @@ import { useSyncConfigStore } from 'src/stores/sync_config.js'
import messages from 'src/i18n/messages' import messages from 'src/i18n/messages'
import localeService from 'src/services/locale/locale.service.js' import localeService from 'src/services/locale/locale.service.js'
// Helper to unwrap reactive proxies
window.toValue = toValue
export default { export default {
name: 'app', name: 'app',
components: { components: {

View file

@ -39,8 +39,8 @@ import { useUserHighlightStore } from 'src/stores/user_highlight.js'
import VBodyScrollLock from 'src/directives/body_scroll_lock' import VBodyScrollLock from 'src/directives/body_scroll_lock'
import { import {
instanceDefaultConfig, instanceDefaultConfigDefinitions,
staticOrApiConfigDefault, instanceIdentityDefaultDefinitions,
} from 'src/modules/default_config_state.js' } from 'src/modules/default_config_state.js'
let staticInitialResults = null let staticInitialResults = null
@ -169,17 +169,21 @@ const setSettings = async ({ apiConfig, staticConfig, store }) => {
config = Object.assign({}, staticConfig, apiConfig) config = Object.assign({}, staticConfig, apiConfig)
} }
const copyInstanceOption = ({ source, destination }) => { const copyInstanceOption = ({ source, definition = { required: true }, destination }) => {
if (typeof config[source] !== 'undefined') { const value = config[source]
useInstanceStore().set({ path: destination, value: config[source] }) let { required, type, default: defaultValue } = definition
} if (type == null && defaultValue != null) type = typeof defaultValue
if (required && value == null) return
if (type != null && typeof value !== type) return
useInstanceStore().set({ path: destination, value })
} }
Object.keys(staticOrApiConfigDefault) Object.entries(instanceIdentityDefaultDefinitions)
.map((k) => ({ source: k, destination: `instanceIdentity.${k}` })) .map(([source, definition]) => ({ source, definition, destination: `instanceIdentity.${source}` }))
.forEach(copyInstanceOption) .forEach(copyInstanceOption)
Object.keys(instanceDefaultConfig) Object.keys(instanceDefaultConfigDefinitions)
.map((k) => ({ source: k, destination: `prefsStorage.${k}` })) .map(([source, definition]) => ({ source, definition, destination: `prefsStorage.${source}` }))
.forEach(copyInstanceOption) .forEach(copyInstanceOption)
useAuthFlowStore().setInitialStrategy(config.loginMethod) useAuthFlowStore().setInitialStrategy(config.loginMethod)

View file

@ -1,163 +1,514 @@
const browserLocale = (navigator.language || 'en').split('-')[0] const browserLocale = (navigator.language || 'en').split('-')[0]
const convertDefinitions = definitions => Object.fromEntries(
Object.entries(definitions).map(([k, v]) => [
k,
v.default == null ? null : v.default,
]),
)
/// Instance config entries provided by static config or pleroma api /// Instance config entries provided by static config or pleroma api
/// Put settings here only if it does not make sense for a normal user /// Put settings here only if it does not make sense for a normal user
/// to override it. /// to override it.
export const staticOrApiConfigDefault = { export const instanceIdentityDefaultDefinitions = {
name: 'PleromaFE', style: {
theme: 'pleroma-dark', description: 'Instance default style name',
palette: null, type: 'string',
style: null, required: false,
themeChecksum: undefined, },
defaultAvatar: '/images/avi.png', palette: {
defaultBanner: '/images/banner.png', description: 'Instance default palette name',
background: '/static/aurora_borealis.jpg', type: 'string',
embeddedToS: true, required: false,
logo: '/static/logo.svg', },
logoMargin: '.2em', theme: {
logoMask: true, description: 'Instance default theme name',
logoLeft: false, type: 'string',
redirectRootLogin: '/main/friends', required: false,
redirectRootNoLogin: '/main/all', },
hideSitename: false, defaultAvatar: {
nsfwCensorImage: null, description: "Default avatar image to use when user doesn't have one set",
showFeaturesPanel: true, type: 'string',
showInstanceSpecificPanel: false, default: '/images/avi.png',
},
defaultBanner: {
description: "Default banner image to use when user doesn't have one set",
type: 'string',
default: '/images/banner.png',
},
background: {
description: 'Instance background/wallpaper',
type: 'string',
default: '/static/aurora_borealis.jpg',
},
embeddedToS: {
description: 'Whether to show Terms of Service title bar',
type: 'boolean',
default: true,
},
logo: {
description: 'Instance logo',
type: 'string',
default: '/static/logo.svg',
},
logoMargin: {
description: 'Margin for logo (spacing above/below)',
type: 'string',
default: '.2em',
},
logoMask: {
description:
'Use logo as a mask (works well for monochrome/transparent logos)',
type: 'boolean',
default: true,
},
logoLeft: {
description: 'Show logo on the left side of navbar',
type: 'boolean',
default: false,
},
redirectRootLogin: {
description: 'Where to redirect user after login',
type: 'string',
default: '/main/friends',
},
redirectRootNoLogin: {
description: 'Where to redirect anonymous visitors',
type: 'string',
default: '/main/all',
},
hideSitename: {
description: 'Hide the instance name in navbar',
type: 'boolean',
default: false,
},
nsfwCensorImage: {
description: 'Default NSFW censor image',
type: 'string',
required: false,
},
showFeaturesPanel: {
description: 'Show features panel to anonymous visitors',
type: 'boolean',
default: true,
},
showInstanceSpecificPanel: {
description: 'Show instance-specific panel',
type: 'boolean',
default: false,
},
// Html stuff // Html stuff
instanceSpecificPanelContent: '', instanceSpecificPanelContent: {
tos: '', description: 'HTML of Instance-specific panel',
type: 'string',
required: false,
},
tos: {
description: 'HTML of Terms of Service panel',
type: 'string',
required: false,
},
} }
export const instanceIdentityDefault = convertDefinitions(instanceIdentityDefaultDefinitions)
/// This object contains setting entries that makes sense /// This object contains setting entries that makes sense
/// at the user level. The defaults can also be overriden by /// at the user level. The defaults can also be overriden by
/// instance admins in the frontend_configuration endpoint or static config. /// instance admins in the frontend_configuration endpoint or static config.
export const instanceDefaultConfig = { export const instanceDefaultConfigDefinitions = {
expertLevel: 0, // used to track which settings to show and hide expertLevel: {
hideISP: false, description: 'Used to track which settings to show and hide in settings modal',
hideInstanceWallpaper: false, type: 'number', // not a boolean so we could potentially make multiple levels of expert-ness
hideShoutbox: false, default: 0,
// bad name: actually hides posts of muted USERS },
hideMutedPosts: false, hideISP: {
hideMutedThreads: true, description: 'Hide Instance-specific panel',
hideWordFilteredPosts: false, default: false,
muteBotStatuses: false, },
muteSensitiveStatuses: false, hideInstanceWallpaper: {
collapseMessageWithSubject: false, description: 'Hide Instance default background',
padEmoji: true, default: false,
hideAttachmentsInConv: false, },
hideScrobbles: false, hideShoutbox: {
hideScrobblesAfter: '2d', description: 'Hide shoutbox if present',
maxThumbnails: 16, default: false,
loopVideo: true, },
loopVideoSilentOnly: true, hideMutedPosts: { // bad name
description: 'Hide posts of muted users entirely',
default: false,
},
hideMutedThreads: {
description: 'Hide muted threads entirely',
default: true,
},
hideWordFilteredPosts: {
description: 'Hide wordfiltered posts entirely',
default: false,
},
muteBotStatuses: {
description: 'Mute posts made by bots',
default: false,
},
muteSensitiveStatuses: {
description: 'Mute posts marked as NSFW',
default: false,
},
collapseMessageWithSubject: {
description: 'Collapse posts with subject',
default: false,
},
padEmoji: {
description: 'Pad emoji with spaces when using emoji picker',
default: true,
},
hideAttachmentsInConv: {
description: 'Hide attachments',
default: false,
},
hideScrobbles: {
description: 'Hide scrobbles',
default: false,
},
hideScrobblesAfter: {
description: 'Hide scrobbles older than',
default: '2d',
},
maxThumbnails: {
description: 'Maximum attachments to show',
default: 16,
},
loopVideo: {
description: 'Loop videos',
default: true,
},
loopVideoSilentOnly: {
description: 'Loop only videos without sound',
default: true,
},
/// This is not the streaming API configuration, but rather an option /// This is not the streaming API configuration, but rather an option
/// for automatically loading new posts into the timeline without /// for automatically loading new posts into the timeline without
/// the user clicking the Show New button. /// the user clicking the Show New button.
streaming: false, streaming: {
emojiReactionsOnTimeline: true, description: 'Automatically show new posts',
alwaysShowNewPostButton: false, default: false,
autohideFloatingPostButton: false, },
pauseOnUnfocused: true, pauseOnUnfocused: {
stopGifs: true, description: 'Pause showing new posts when tab is unfocused',
replyVisibility: 'all', default: true,
thirdColumnMode: 'notifications', },
emojiReactionsOnTimeline: {
description: 'Show emoji reactions on timeline',
default: true,
},
alwaysShowNewPostButton: {
description: 'Always show mobile "new post" button, even in desktop mode',
default: false,
},
autohideFloatingPostButton: {
description: 'Automatically hide mobile "new post" button when scrolling down',
default: false,
},
stopGifs: {
description: 'Play animated gifs on hover only',
default: true,
},
replyVisibility: {
description: 'Type of replies to show',
default: 'all',
},
thirdColumnMode: {
description: 'What to display in third column',
default: 'notifications',
},
notificationVisibility: { notificationVisibility: {
follows: true, description: 'What types of notifications to show',
mentions: true, default: {
statuses: true, follows: true,
likes: true, mentions: true,
repeats: true, statuses: true,
moves: true, likes: true,
emojiReactions: true, repeats: true,
followRequest: true, moves: true,
reports: true, emojiReactions: true,
chatMention: true, followRequest: true,
polls: true, reports: true,
chatMention: true,
polls: true,
},
}, },
notificationNative: { notificationNative: {
follows: true, description: 'What type of notifications to show desktop notification for',
mentions: true, default: {
statuses: true, follows: true,
likes: false, mentions: true,
repeats: false, statuses: true,
moves: false, likes: false,
emojiReactions: false, repeats: false,
followRequest: true, moves: false,
reports: true, emojiReactions: false,
chatMention: true, followRequest: true,
polls: true, reports: true,
chatMention: true,
polls: true,
},
},
webPushNotifications: {
description: 'Use WebPush',
default: false,
},
webPushAlwaysShowNotifications: {
description: 'Ignore filter when using WebPush',
default: false,
},
interfaceLanguage: {
description: 'UI language',
default: browserLocale,
},
hideScopeNotice: {
description: 'Hide scope notification',
default: false,
},
scopeCopy: {
description: 'Copy scope like mastodon does',
default: true,
},
subjectLineBehavior: {
description: 'How to treat subject line',
default: 'email',
},
alwaysShowSubjectInput: {
description: 'Always show subject line field',
default: true,
},
minimalScopesMode: {
description: 'Minimize amount of options shown in scope selector',
default: false,
}, },
webPushNotifications: false,
webPushAlwaysShowNotifications: false,
interfaceLanguage: browserLocale,
hideScopeNotice: false,
scopeCopy: true,
subjectLineBehavior: 'email',
alwaysShowSubjectInput: true,
minimalScopesMode: false,
// This hides statuses filtered via a word filter // This hides statuses filtered via a word filter
hideFilteredStatuses: false, hideFilteredStatuses: {
description: 'Hide wordfiltered entirely',
default: false,
},
// Confirmations // Confirmations
modalOnRepeat: false, modalOnRepeat: {
modalOnUnfollow: false, description: 'Show confirmation modal for repeat',
modalOnBlock: true, default: false,
modalOnMute: false, },
modalOnMuteConversation: false, modalOnUnfollow: {
modalOnMuteDomain: true, description: 'Show confirmation modal for unfollow',
modalOnDelete: true, default: false,
modalOnLogout: true, },
modalOnApproveFollow: false, modalOnBlock: {
modalOnDenyFollow: false, description: 'Show confirmation modal for block',
modalOnRemoveUserFromFollowers: false, default: true,
},
modalOnMute: {
description: 'Show confirmation modal for mute',
default: false,
},
modalOnMuteConversation: {
description: 'Show confirmation modal for mute conversation',
default: false,
},
modalOnMuteDomain: {
description: 'Show confirmation modal for mute domain',
default: true,
},
modalOnDelete: {
description: 'Show confirmation modal for delete',
default: true,
},
modalOnLogout: {
description: 'Show confirmation modal for logout',
default: true,
},
modalOnApproveFollow: {
description: 'Show confirmation modal for approve follow',
default: false,
},
modalOnDenyFollow: {
description: 'Show confirmation modal for deny follow',
default: false,
},
modalOnRemoveUserFromFollowers: {
description: 'Show confirmation modal for follower removal',
default: false,
},
// Expiry confirmations/default actions // Expiry confirmations/default actions
onMuteDefaultAction: 'ask', onMuteDefaultAction: {
onBlockDefaultAction: 'ask', description: 'Default action when muting user',
default: 'ask',
},
onBlockDefaultAction: {
description: 'Default action when blocking user',
default: 'ask',
},
modalMobileCenter: false, modalMobileCenter: {
playVideosInModal: false, description: 'Center mobile dialogs vertically',
useContainFit: true, default: false,
disableStickyHeaders: false, },
showScrollbars: false, playVideosInModal: {
userPopoverAvatarAction: 'open', description: 'Play videos in gallery view',
userPopoverOverlay: false, default: false,
userCardLeftJustify: false, },
userCardHidePersonalMarks: false, useContainFit: {
forcedRoundness: -1, description: 'Use object-fit: contain for attachments',
greentext: false, default: true,
mentionLinkShowTooltip: true, },
mentionLinkShowAvatar: false, disableStickyHeaders: {
mentionLinkFadeDomain: true, description: 'Disable sticky headers',
mentionLinkShowYous: false, default: false,
mentionLinkBoldenYou: true, },
hidePostStats: false, showScrollbars: {
hideBotIndication: false, description: 'Always show scrollbars',
hideUserStats: false, default: false,
virtualScrolling: true, },
sensitiveByDefault: false, userPopoverAvatarAction: {
conversationDisplay: 'linear', description: 'What to do when clicking popover avatar',
conversationTreeAdvanced: false, default: 'open',
conversationOtherRepliesButton: 'below', },
conversationTreeFadeAncestors: false, userPopoverOverlay: {
showExtraNotifications: true, description: 'Overlay user popover with centering on avatar',
showExtraNotificationsTip: true, default: false,
showChatsInExtraNotifications: true, },
showAnnouncementsInExtraNotifications: true, userCardLeftJustify: {
showFollowRequestsInExtraNotifications: true, description: 'Justify user bio to the left',
maxDepthInThread: 6, default: false,
autocompleteSelect: false, },
closingDrawerMarksAsSeen: true, userCardHidePersonalMarks: {
unseenAtTop: false, description: 'Hide highlight/personal note in user view',
ignoreInactionableSeen: false, default: false,
unsavedPostAction: 'confirm', },
autoSaveDraft: false, forcedRoundness: {
useAbsoluteTimeFormat: false, description: 'Force roundness of the theme',
absoluteTimeFormatMinAge: '0d', default: -1,
absoluteTime12h: '24h', },
greentext: {
description: 'Highlight plaintext >quotes',
default: false,
},
mentionLinkShowTooltip: {
description: 'Show tooltips for mention links',
default: true,
},
mentionLinkShowAvatar: {
description: 'Show avatar next to mention link',
default: false,
},
mentionLinkFadeDomain: {
description: 'Mute (fade) domain name in mention links if configured to show it',
default: true,
},
mentionLinkShowYous: {
description: 'Show (you)s when you are mentioned',
default: false,
},
mentionLinkBoldenYou: {
description: 'Boldern mentionlink of you',
default: true,
},
hidePostStats: {
description: 'Hide post stats (rt, favs)',
default: false,
},
hideBotIndication: {
description: 'Hide bot indicator',
default: false,
},
hideUserStats: {
description: 'Hide user stats (followers etc)',
default: false,
},
virtualScrolling: {
description: 'Timeline virtual scrolling',
default: true,
},
sensitiveByDefault: {
description: 'Assume attachments are NSFW by default',
default: false,
},
conversationDisplay: {
description: 'Style of conversation display',
default: 'linear',
},
conversationTreeAdvanced: {
description: 'Advanced features of tree view conversation',
default: false,
},
conversationOtherRepliesButton: {
description: 'Where to show "other replies" in tree conversation view',
default: 'below',
},
conversationTreeFadeAncestors: {
description: 'Fade ancestors in tree conversation view',
default: false,
},
showExtraNotifications: {
description: 'Show extra notifications (chats, announcements etc) in notification panel',
default: true,
},
showExtraNotificationsTip: {
description: 'Show tip for extra notifications (that user can remove them)',
default: true,
},
showChatsInExtraNotifications: {
description: 'Show chat messages in notifications',
default: true,
},
showAnnouncementsInExtraNotifications: {
description: 'Show announcements in notifications',
default: true,
},
showFollowRequestsInExtraNotifications: {
description: 'Show follow requests in notifications',
default: true,
},
maxDepthInThread: {
description: 'Maximum depth in tree conversation view',
default: 6,
},
autocompleteSelect: {
description: '',
default: false,
},
closingDrawerMarksAsSeen: {
description: 'Closing mobile notification pane marks everything as seen',
default: true,
},
unseenAtTop: {
description: 'Show unseen notifications above others',
default: false,
},
ignoreInactionableSeen: {
description: 'Treat inactionable (fav, rt etc) notifications as "seen"',
default: false,
},
unsavedPostAction: {
description: 'What to do if post is aborted',
default: 'confirm',
},
autoSaveDraft: {
description: 'Save drafts automatically',
default: false,
},
useAbsoluteTimeFormat: {
description: 'Use absolute time format',
default: false,
},
absoluteTimeFormatMinAge: {
description: 'Show absolute time format only after this post age',
default: '0d',
},
absoluteTime12h: {
description: 'Use 24h time format',
default: '24h',
},
} }
export const instanceDefaultConfig = convertDefinitions(instanceDefaultConfigDefinitions)
export const defaultConfigLocal = { export const defaultConfigLocal = {
hideAttachments: false, hideAttachments: false,
@ -189,6 +540,7 @@ export const defaultConfigLocal = {
themeDebug: false, // debug mode that uses computed backgrounds instead of real ones to debug contrast functions 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 forceThemeRecompilation: false, // flag that forces recompilation on boot even if cache exists
} }
export const LOCAL_ONLY_KEYS = new Set(Object.keys(defaultConfigLocal)) export const LOCAL_ONLY_KEYS = new Set(Object.keys(defaultConfigLocal))
export const makeUndefined = (c) => export const makeUndefined = (c) =>

View file

@ -3,9 +3,9 @@ import { defineStore } from 'pinia'
import { instanceDefaultProperties } from '../modules/config.js' import { instanceDefaultProperties } from '../modules/config.js'
import { import {
instanceDefaultConfig,
defaultConfigLocal, defaultConfigLocal,
staticOrApiConfigDefault, instanceDefaultConfig,
instanceIdentityDefault,
} from '../modules/default_config_state.js' } from '../modules/default_config_state.js'
import apiService from '../services/api/api.service.js' import apiService from '../services/api/api.service.js'
@ -16,7 +16,6 @@ import { ensureFinalFallback } from 'src/i18n/languages.js'
const REMOTE_INTERACTION_URL = '/main/ostatus' const REMOTE_INTERACTION_URL = '/main/ostatus'
const defaultState = { const defaultState = {
// Stuff from apiConfig
name: 'Pleroma FE', name: 'Pleroma FE',
registrationOpen: true, registrationOpen: true,
server: 'http://localhost:4040/', server: 'http://localhost:4040/',
@ -36,7 +35,7 @@ const defaultState = {
// Instance-wide configurations that should not be changed by individual users // Instance-wide configurations that should not be changed by individual users
instanceIdentity: { instanceIdentity: {
...staticOrApiConfigDefault, ...instanceIdentityDefault,
}, },
limits: { limits: {

View file

@ -412,15 +412,13 @@ export const useInterfaceStore = defineStore('interface', {
return result return result
} }
const { style: instanceStyleName, palette: instancePaletteName } =
useInstanceStore()
let { let {
theme: instanceThemeV2Name, theme: instanceThemeName,
themesIndex, style: instanceStyleName,
stylesIndex, palette: instancePaletteName,
palettesIndex, } = useInstanceStore().instanceIdentity
} = useInstanceStore()
let { themesIndex, stylesIndex, palettesIndex } = useInstanceStore()
const { const {
style: userStyleName, style: userStyleName,
@ -447,7 +445,7 @@ export const useInterfaceStore = defineStore('interface', {
console.debug( console.debug(
`Instance V3 palette: ${instancePaletteName}, style: ${instanceStyleName}`, `Instance V3 palette: ${instancePaletteName}, style: ${instanceStyleName}`,
) )
console.debug('Instance V2 theme: ' + instanceThemeV2Name) console.debug('Instance V2 theme: ' + instanceThemeName)
if ( if (
userPaletteName || userPaletteName ||
@ -456,11 +454,11 @@ export const useInterfaceStore = defineStore('interface', {
userStyleCustomData || userStyleCustomData ||
// User V2 overrides instance V3 // User V2 overrides instance V3
((instancePaletteName || instanceStyleName) && ((instancePaletteName || instanceStyleName) &&
instanceThemeV2Name == null && instanceThemeName == null &&
userThemeV2Name == null) userThemeV2Name == null)
) { ) {
// Palette and/or style overrides V2 themes // Palette and/or style overrides V2 themes
instanceThemeV2Name = null instanceThemeName = null
userThemeV2Name = null userThemeV2Name = null
userThemeV2Source = null userThemeV2Source = null
userThemeV2Snapshot = null userThemeV2Snapshot = null
@ -470,7 +468,7 @@ export const useInterfaceStore = defineStore('interface', {
userThemeV2Name || userThemeV2Name ||
userThemeV2Snapshot || userThemeV2Snapshot ||
userThemeV2Source || userThemeV2Source ||
instanceThemeV2Name instanceThemeName
) { ) {
majorVersionUsed = 'v2' majorVersionUsed = 'v2'
} else { } else {
@ -588,7 +586,7 @@ export const useInterfaceStore = defineStore('interface', {
'theme', 'theme',
themesIndex, themesIndex,
userThemeV2Source || userThemeV2Snapshot, userThemeV2Source || userThemeV2Snapshot,
userThemeV2Name || instanceThemeV2Name, userThemeV2Name || instanceThemeName,
) )
this.themeNameUsed = theme.nameUsed this.themeNameUsed = theme.nameUsed
this.themeDataUsed = theme.dataUsed this.themeDataUsed = theme.dataUsed

View file

@ -643,7 +643,9 @@ export const useSyncConfigStore = defineStore('sync_config', {
vuexState.config = vuexState.config ?? {} vuexState.config = vuexState.config ?? {}
const migratedEntries = new Set(vuexState.config._syncMigration ?? []) const migratedEntries = new Set(vuexState.config._syncMigration ?? [])
console.debug(`Already migrated Values: ${[...migratedEntries].join() || '[none]'}`) console.debug(
`Already migrated Values: ${[...migratedEntries].join() || '[none]'}`,
)
Object.entries(oldDefaultConfigSync).forEach(([key, value]) => { Object.entries(oldDefaultConfigSync).forEach(([key, value]) => {
const oldValue = vuexState.config[key] const oldValue = vuexState.config[key]

View file

@ -1,6 +1,8 @@
import { cloneDeep } from 'lodash' import { cloneDeep } from 'lodash'
import { createPinia, setActivePinia } from 'pinia' import { createPinia, setActivePinia } from 'pinia'
import { CURRENT_UPDATE_COUNTER } from 'src/components/update_notification/update_notification.js'
import { import {
_getAllFlags, _getAllFlags,
_getRecentData, _getRecentData,
@ -15,7 +17,6 @@ import {
useSyncConfigStore, useSyncConfigStore,
VERSION, VERSION,
} from 'src/stores/sync_config.js' } from 'src/stores/sync_config.js'
import { CURRENT_UPDATE_COUNTER } from 'src/components/update_notification/update_notification.js'
describe('The SyncConfig store', () => { describe('The SyncConfig store', () => {
beforeEach(() => { beforeEach(() => {