diff --git a/src/boot/after_store.js b/src/boot/after_store.js
index 5c2aaa6ef..7d1995347 100644
--- a/src/boot/after_store.js
+++ b/src/boot/after_store.js
@@ -39,8 +39,8 @@ import { useUserHighlightStore } from 'src/stores/user_highlight.js'
import VBodyScrollLock from 'src/directives/body_scroll_lock'
import {
- instanceDefaultConfigDefinitions,
- instanceIdentityDefaultDefinitions,
+ INSTANCE_DEFAULT_CONFIG_DEFINITIONS,
+ INSTANCE_IDENTITY_DEFAULT_DEFINITIONS,
} from 'src/modules/default_config_state.js'
let staticInitialResults = null
@@ -83,7 +83,7 @@ const getInstanceConfig = async ({ store }) => {
const res = await preloadFetch('/api/v1/instance')
if (res.ok) {
const data = await res.json()
- const textlimit = data.max_toot_chars
+ const textLimit = data.max_toot_chars
const vapidPublicKey = data.pleroma.vapid_public_key
useInstanceCapabilitiesStore().set(
@@ -91,8 +91,8 @@ const getInstanceConfig = async ({ store }) => {
data.pleroma,
)
useInstanceStore().set({
- path: 'textlimit',
- value: textlimit,
+ path: 'limits.textLimit',
+ value: textLimit,
})
useInstanceStore().set({
path: 'accountApprovalRequired',
@@ -169,22 +169,19 @@ const setSettings = async ({ apiConfig, staticConfig, store }) => {
config = Object.assign({}, staticConfig, apiConfig)
}
- const copyInstanceOption = ({ source, definition = { required: true }, destination }) => {
- const 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
+ Object.keys(INSTANCE_IDENTITY_DEFAULT_DEFINITIONS).forEach((source) =>
+ useInstanceStore().set({
+ value: config[source],
+ path: `instanceIdentity.${source}`,
+ }),
+ )
- useInstanceStore().set({ path: destination, value })
- }
-
- Object.entries(instanceIdentityDefaultDefinitions)
- .map(([source, definition]) => ({ source, definition, destination: `instanceIdentity.${source}` }))
- .forEach(copyInstanceOption)
- Object.keys(instanceDefaultConfigDefinitions)
- .map(([source, definition]) => ({ source, definition, destination: `prefsStorage.${source}` }))
- .forEach(copyInstanceOption)
+ Object.keys(INSTANCE_DEFAULT_CONFIG_DEFINITIONS).forEach((source) =>
+ useInstanceStore().set({
+ value: config[source],
+ path: `prefsStorage.${source}`,
+ }),
+ )
useAuthFlowStore().setInitialStrategy(config.loginMethod)
}
@@ -194,7 +191,7 @@ const getTOS = async ({ store }) => {
const res = await window.fetch('/static/terms-of-service.html')
if (res.ok) {
const html = await res.text()
- useInstanceStore().set({ name: 'instanceIdentity.tos', value: html })
+ useInstanceStore().set({ path: 'instanceIdentity.tos', value: html })
} else {
throw res
}
@@ -543,7 +540,7 @@ const afterStoreSetup = async ({ pinia, store, storageError, i18n }) => {
typeof overrides.target !== 'undefined'
? overrides.target
: window.location.origin
- useInstanceStore().set({ name: 'server', value: server })
+ useInstanceStore().set({ path: 'server', value: server })
await setConfig({ store })
try {
diff --git a/src/components/features_panel/features_panel.js b/src/components/features_panel/features_panel.js
index 106da1487..10deda250 100644
--- a/src/components/features_panel/features_panel.js
+++ b/src/components/features_panel/features_panel.js
@@ -15,7 +15,7 @@ const FeaturesPanel = {
'mediaProxyAvailable',
]),
...mapState(useInstanceStore, {
- textlimit: (store) => store.limits.textlimit,
+ textLimit: (store) => store.limits.textLimit,
uploadlimit: (store) =>
fileSizeFormatService.fileSizeFormat(store.limits.uploadlimit),
}),
diff --git a/src/components/features_panel/features_panel.vue b/src/components/features_panel/features_panel.vue
index 4270436fa..f15ad0edb 100644
--- a/src/components/features_panel/features_panel.vue
+++ b/src/components/features_panel/features_panel.vue
@@ -24,7 +24,7 @@
{{ $t('features_panel.media_proxy') }}
{{ $t('features_panel.scope_options') }}
- {{ $t('features_panel.text_limit') }} = {{ textlimit }}
+ {{ $t('features_panel.text_limit') }} = {{ textLimit }}
{{ $t('features_panel.upload_limit') }} = {{ uploadlimit.num }} {{ $t('upload.file_size_units.' + uploadlimit.unit) }}
diff --git a/src/components/post_status_form/post_status_form.js b/src/components/post_status_form/post_status_form.js
index 2530392bc..20140df19 100644
--- a/src/components/post_status_form/post_status_form.js
+++ b/src/components/post_status_form/post_status_form.js
@@ -290,7 +290,7 @@ const PostStatusForm = {
return this.newStatus.spoilerText.length
},
statusLengthLimit() {
- return useInstanceStore().textlimit
+ return useInstanceStore().limits.textLimit
},
hasStatusLengthLimit() {
return this.statusLengthLimit > 0
diff --git a/src/modules/default_config_state.js b/src/modules/default_config_state.js
index 89047f314..4606c67a3 100644
--- a/src/modules/default_config_state.js
+++ b/src/modules/default_config_state.js
@@ -1,16 +1,19 @@
+import { get, set } from 'lodash'
+
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,
- ]),
-)
+export const convertDefinitions = (definitions) =>
+ Object.fromEntries(
+ Object.entries(definitions).map(([k, v]) => {
+ const defaultValue = v.default ?? null
+ return [k, defaultValue]
+ }),
+ )
/// Instance config entries provided by static config or pleroma api
/// Put settings here only if it does not make sense for a normal user
/// to override it.
-export const instanceIdentityDefaultDefinitions = {
+export const INSTANCE_IDENTITY_DEFAULT_DEFINITIONS = {
style: {
description: 'Instance default style name',
type: 'string',
@@ -110,14 +113,17 @@ export const instanceIdentityDefaultDefinitions = {
required: false,
},
}
-export const instanceIdentityDefault = convertDefinitions(instanceIdentityDefaultDefinitions)
+export const INSTANCE_IDENTITY_DEFAULT = convertDefinitions(
+ INSTANCE_IDENTITY_DEFAULT_DEFINITIONS,
+)
/// This object contains setting entries that makes sense
/// at the user level. The defaults can also be overriden by
/// instance admins in the frontend_configuration endpoint or static config.
-export const instanceDefaultConfigDefinitions = {
+export const INSTANCE_DEFAULT_CONFIG_DEFINITIONS = {
expertLevel: {
- description: 'Used to track which settings to show and hide in settings modal',
+ description:
+ 'Used to track which settings to show and hide in settings modal',
type: 'number', // not a boolean so we could potentially make multiple levels of expert-ness
default: 0,
},
@@ -133,7 +139,8 @@ export const instanceDefaultConfigDefinitions = {
description: 'Hide shoutbox if present',
default: false,
},
- hideMutedPosts: { // bad name
+ hideMutedPosts: {
+ // bad name
description: 'Hide posts of muted users entirely',
default: false,
},
@@ -205,7 +212,8 @@ export const instanceDefaultConfigDefinitions = {
default: false,
},
autohideFloatingPostButton: {
- description: 'Automatically hide mobile "new post" button when scrolling down',
+ description:
+ 'Automatically hide mobile "new post" button when scrolling down',
default: false,
},
stopGifs: {
@@ -400,7 +408,8 @@ export const instanceDefaultConfigDefinitions = {
default: false,
},
mentionLinkFadeDomain: {
- description: 'Mute (fade) domain name in mention links if configured to show it',
+ description:
+ 'Mute (fade) domain name in mention links if configured to show it',
default: true,
},
mentionLinkShowYous: {
@@ -448,7 +457,8 @@ export const instanceDefaultConfigDefinitions = {
default: false,
},
showExtraNotifications: {
- description: 'Show extra notifications (chats, announcements etc) in notification panel',
+ description:
+ 'Show extra notifications (chats, announcements etc) in notification panel',
default: true,
},
showExtraNotificationsTip: {
@@ -507,41 +517,141 @@ export const instanceDefaultConfigDefinitions = {
description: 'Use 24h time format',
default: '24h',
},
+ themeChecksum: {
+ description: 'Checksum of theme used',
+ type: 'string',
+ required: false,
+ },
}
-export const instanceDefaultConfig = convertDefinitions(instanceDefaultConfigDefinitions)
+export const INSTANCE_DEFAULT_CONFIG = convertDefinitions(
+ INSTANCE_DEFAULT_CONFIG_DEFINITIONS,
+)
-export const defaultConfigLocal = {
- hideAttachments: false,
- hideAttachmentsInConv: false,
- hideNsfw: true,
- useOneClickNsfw: false,
- preloadImage: true,
- 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,
- imageCompression: true,
- useStreamingApi: false,
- underlay: 'none',
- fontInterface: undefined,
- fontInput: undefined,
- fontPosts: undefined,
- fontMonospace: undefined,
- 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
+export const LOCAL_DEFAULT_CONFIG_DEFINITIONS = {
+ // TODO these two used to be separate but since separation feature got broken it doesn't matter
+ hideAttachments: {
+ description: 'Hide attachments in timeline',
+ default: false,
+ },
+ hideAttachmentsInConv: {
+ description: 'Hide attachments in coversation',
+ default: false,
+ },
+ hideNsfw: {
+ description: 'Hide nsfw posts',
+ default: true,
+ },
+ useOneClickNsfw: {
+ description: 'Open NSFW images directly in media modal',
+ default: false,
+ },
+ preloadImage: {
+ description: 'Preload images for NSFW',
+ default: true,
+ },
+ postContentType: {
+ description: 'Default post content type',
+ default: 'text/plain',
+ },
+ sidebarRight: {
+ description: 'Reverse order of columns',
+ default: false,
+ },
+ sidebarColumnWidth: {
+ description: 'Sidebar column width',
+ default: '25rem',
+ },
+ contentColumnWidth: {
+ description: 'Middle column width',
+ default: '45rem',
+ },
+ notifsColumnWidth: {
+ description: 'Notifications column width',
+ default: '25rem',
+ },
+ themeEditorMinWidth: {
+ description: 'Hack for theme editor on mobile',
+ default: '0rem',
+ },
+ emojiReactionsScale: {
+ description: 'Emoji reactions scale factor',
+ default: 0.5,
+ },
+ textSize: {
+ description: 'Font size',
+ default: '1rem',
+ },
+ emojiSize: {
+ description: 'Emoji size',
+ default: '2.2rem',
+ },
+ navbarSize: {
+ description: 'Navbar size',
+ default: '3.5rem',
+ },
+ panelHeaderSize: {
+ description: 'Panel header size',
+ default: '3.2rem',
+ },
+ navbarColumnStretch: {
+ description: 'Stretch navbar to match columns width',
+ default: false,
+ },
+ mentionLinkDisplay: {
+ description: 'How to display mention links',
+ default: 'short',
+ },
+ imageCompression: {
+ description: 'Image compression (WebP/JPEG)',
+ default: true,
+ },
+ alwaysUseJpeg: {
+ description: 'Compress images using JPEG only',
+ default: false,
+ },
+ useStreamingApi: {
+ description: 'Streaming API (WebSocket)',
+ default: false,
+ },
+ underlay: {
+ description: 'Underlay override',
+ default: 'none',
+ },
+ fontInterface: {
+ description: 'Interface font override',
+ type: 'string',
+ default: null,
+ },
+ fontInput: {
+ description: 'Input font override',
+ type: 'string',
+ default: null,
+ },
+ fontPosts: {
+ description: 'Post font override',
+ type: 'string',
+ default: null,
+ },
+ fontMonospace: {
+ description: 'Monospace font override',
+ type: 'string',
+ default: null,
+ },
+ themeDebug: {
+ description:
+ 'Debug mode that uses computed backgrounds instead of real ones to debug contrast functions',
+ default: false,
+ },
+ forceThemeRecompilation: {
+ description: 'Flag that forces recompilation on boot even if cache exists',
+ default: false,
+ },
}
+export const LOCAL_DEFAULT_CONFIG = convertDefinitions(
+ LOCAL_DEFAULT_CONFIG_DEFINITIONS,
+)
-export const LOCAL_ONLY_KEYS = new Set(Object.keys(defaultConfigLocal))
+export const LOCAL_ONLY_KEYS = new Set(Object.keys(LOCAL_DEFAULT_CONFIG))
export const makeUndefined = (c) =>
Object.fromEntries(Object.keys(c).map((key) => [key, undefined]))
@@ -550,8 +660,8 @@ export const makeUndefined = (c) =>
/// make sense to be overriden on a instance-wide level.
export const defaultState = {
// Set these to undefined so it does not interfere with default settings check
- ...makeUndefined(instanceDefaultConfig),
- ...makeUndefined(defaultConfigLocal),
+ ...makeUndefined(INSTANCE_DEFAULT_CONFIG),
+ ...makeUndefined(LOCAL_DEFAULT_CONFIG),
// If there are any configurations that does not make sense to
// have instance-wide default, put it here and explain why.
@@ -572,3 +682,53 @@ export const defaultState = {
palette: null,
paletteCustomData: null,
}
+
+export const validateSetting = ({
+ value,
+ path,
+ definition,
+ throwError,
+ defaultState,
+}) => {
+ if (value === undefined) return // only null is allowed as missing value
+ if (get(defaultState, path) === undefined) {
+ const string = `Unknown instance option ${path}, value: ${value}`
+
+ if (throwError) {
+ throw new Error(string)
+ } else {
+ console.error(string)
+ return value
+ }
+ }
+
+ let { required, type, default: defaultValue } = definition
+
+ if (type == null && defaultValue != null) {
+ type = typeof defaultValue
+ }
+
+ if (required && value == null) {
+ const string = `Value required for setting ${path} but was provided nullish; defaulting`
+
+ if (throwError) {
+ throw new Error(string)
+ } else {
+ console.error(string)
+ return defaultValue
+ }
+ }
+
+ if (value !== null && type != null && typeof value !== type) {
+ const string = `Invalid type for setting ${path}: expected type ${type}, got ${typeof value}, value ${value}; defaulting`
+
+ if (throwError) {
+ throw new Error(string)
+ } else {
+ console.error(string)
+ return defaultValue
+ }
+ }
+
+ return value
+}
diff --git a/src/stores/instance.js b/src/stores/instance.js
index f1f31a8d1..71ee05e7a 100644
--- a/src/stores/instance.js
+++ b/src/stores/instance.js
@@ -1,41 +1,146 @@
import { get, set } from 'lodash'
import { defineStore } from 'pinia'
-import { instanceDefaultProperties } from '../modules/config.js'
import {
- defaultConfigLocal,
- instanceDefaultConfig,
- instanceIdentityDefault,
+ convertDefinitions,
+ INSTANCE_DEFAULT_CONFIG,
+ INSTANCE_DEFAULT_CONFIG_DEFINITIONS,
+ INSTANCE_IDENTITY_DEFAULT,
+ INSTANCE_IDENTITY_DEFAULT_DEFINITIONS,
+ LOCAL_DEFAULT_CONFIG,
+ LOCAL_DEFAULT_CONFIG_DEFINITIONS,
+ validateSetting,
} from '../modules/default_config_state.js'
import apiService from '../services/api/api.service.js'
import { useInterfaceStore } from 'src/stores/interface.js'
-import { ensureFinalFallback } from 'src/i18n/languages.js'
-
const REMOTE_INTERACTION_URL = '/main/ostatus'
-const defaultState = {
- name: 'Pleroma FE',
- registrationOpen: true,
- server: 'http://localhost:4040/',
- textlimit: 5000,
- privateMode: false,
- federating: true,
- federationPolicy: null,
- themesIndex: null,
- stylesIndex: null,
- palettesIndex: null,
- themeData: null, // used for theme editor v2
- vapidPublicKey: null,
+const ROOT_STATE_DEFINITIONS = {
+ name: {
+ type: 'string',
+ default: 'PleromaFE',
+ },
+ registrationOpen: {
+ required: true,
+ type: 'boolean',
+ },
+ server: {
+ description: 'Server URL',
+ required: true,
+ type: 'string',
+ },
+ privateMode: {
+ description: 'Private instance?',
+ required: true,
+ type: 'boolean',
+ },
+ federating: {
+ description: 'Is federation enabled?',
+ required: true,
+ type: 'boolean',
+ },
+ federationPolicy: {
+ description: '????',
+ required: true,
+ type: 'object',
+ },
+
+ // Indexes of themes/styles/palettes
+ themesIndex: {
+ required: true,
+ type: 'object',
+ },
+ stylesIndex: {
+ required: true,
+ type: 'object',
+ },
+ palettesIndex: {
+ required: true,
+ type: 'object',
+ },
+
+ themeData: {
+ description: 'Used for theme v2 editor',
+ required: true,
+ type: 'object',
+ },
+ vapidPublicKey: {
+ description: 'Used for WebPush',
+ required: true,
+ type: 'string',
+ },
// Stuff from static/config.json
- loginMethod: 'password',
- disableUpdateNotification: false,
+ loginMethod: {
+ description: 'Login method (token/password)',
+ default: 'password',
+ },
+ disableUpdateNotification: {
+ description: 'Disable update notification (pleroma-tan one)',
+ default: false,
+ },
+ knownDomains: {
+ description: 'List of known domains; used for domain list for domain mutes',
+ default: [],
+ },
+ // Moderation stuff
+ staffAccounts: {
+ description: 'List of staff accounts',
+ default: [],
+ },
+ accountActivationRequired: {
+ description:
+ 'Account activation (by email or admin) required after registration',
+ required: true,
+ type: 'boolean',
+ },
+ accountApprovalRequired: {
+ description: 'Admin approval required after registration',
+ required: true,
+ type: 'boolean',
+ },
+ birthdayRequired: {
+ description: 'Require birthday entry when registering',
+ required: true,
+ type: 'boolean',
+ },
+ birthdayMinAge: {
+ description: 'Minimum age required for registration',
+ default: 0,
+ },
+ restrictedNicknames: {
+ description: 'List of nicknames that are not allowed',
+ default: [],
+ },
+ localBubbleInstances: {
+ description: "Akkoma's bubble feature, list of instances",
+ default: [],
+ }, // Akkoma
+
+ // Version Information
+ backendVersion: {
+ required: true,
+ type: 'string',
+ },
+ backendRepository: {
+ required: true,
+ type: 'string',
+ },
+ frontendVersion: {
+ required: true,
+ type: 'string',
+ },
+}
+const ROOT_STATE = convertDefinitions(ROOT_STATE_DEFINITIONS)
+
+const DEFAULT_STATE = {
+ ...ROOT_STATE,
// Instance-wide configurations that should not be changed by individual users
instanceIdentity: {
- ...instanceIdentityDefault,
+ ...INSTANCE_IDENTITY_DEFAULT,
},
limits: {
@@ -44,6 +149,7 @@ const defaultState = {
backgroundlimit: null,
uploadlimit: null,
fieldsLimits: null,
+ textLimit: null,
pollLimits: {
max_options: 4,
max_option_chars: 255,
@@ -54,50 +160,53 @@ const defaultState = {
// Instance admins can override default settings for the whole instance
prefsStorage: {
- ...instanceDefaultConfig,
- ...defaultConfigLocal,
+ ...INSTANCE_DEFAULT_CONFIG,
+ ...LOCAL_DEFAULT_CONFIG,
},
-
- // Known domains list for user's domain-muting
- knownDomains: [],
-
- // Moderation stuff
- staffAccounts: [],
- accountActivationRequired: null,
- accountApprovalRequired: null,
- birthdayRequired: false,
- birthdayMinAge: 0,
- restrictedNicknames: [],
- localBubbleInstances: [], // Akkoma
-
- // Version Information
- backendVersion: '',
- backendRepository: '',
- frontendVersion: '',
}
+console.log('===', ROOT_STATE_DEFINITIONS)
export const useInstanceStore = defineStore('instance', {
- state: () => ({ ...defaultState }),
+ state: () => ({ ...DEFAULT_STATE }),
getters: {
- instanceDefaultConfig(state) {
- return instanceDefaultProperties
- .map((key) => [key, state[key]])
- .reduce((acc, [key, value]) => ({ ...acc, [key]: value }), {})
- },
instanceDomain(state) {
return new URL(this.server).hostname
},
},
actions: {
- set({ path, name, value }) {
- if (get(defaultState, path ?? name) === undefined)
- console.error(
- `Unknown instance option ${path ?? name}, value: ${value}`,
- )
+ set({ path, value }) {
+ let definition
+ const pathArray = path.split('.')
+ const subpath = pathArray[1] ?? pathArray[0]
- set(this, path ?? name, value)
+ if (path.startsWith('instanceIdentity.')) {
+ definition = INSTANCE_IDENTITY_DEFAULT_DEFINITIONS[subpath]
+ } else if (path.startsWith('prefsStorage.')) {
+ definition = {
+ ...LOCAL_DEFAULT_CONFIG_DEFINITIONS,
+ ...INSTANCE_DEFAULT_CONFIG_DEFINITIONS,
+ }[subpath]
+ } else if (path.startsWith('limits.')) {
+ definition =
+ path === 'limits.pollLimits' || path === 'limits.fieldsLimits'
+ ? { required: true, type: 'object' }
+ : { required: true, type: 'number' }
+ } else {
+ const definitions = ROOT_STATE_DEFINITIONS
+ definition = definitions[subpath]
+ }
- if ((path ?? name) === 'name') useInterfaceStore().setPageTitle()
+ const finalValue = validateSetting({
+ path,
+ value,
+ definition,
+ throwError: true,
+ defaultState: DEFAULT_STATE,
+ })
+
+ set(this, path, finalValue)
+
+ if (path === 'name') useInterfaceStore().setPageTitle()
},
async getKnownDomains() {
try {
diff --git a/src/stores/local_config.js b/src/stores/local_config.js
index 096d0b3f1..b81a55408 100644
--- a/src/stores/local_config.js
+++ b/src/stores/local_config.js
@@ -4,14 +4,17 @@ import { toRaw } from 'vue'
import { useInstanceStore } from 'src/stores/instance'
-import { defaultState as configDefaultState } from 'src/modules/default_config_state'
+import {
+ LOCAL_DEFAULT_CONFIG,
+ LOCAL_DEFAULT_CONFIG_DEFINITIONS
+} from 'src/modules/default_config_state'
export const defaultState = {
prefsStorage: {
- ...configDefaultState,
+ ...LOCAL_DEFAULT_CONFIG,
},
tempStorage: {
- ...configDefaultState,
+ ...LOCAL_DEFAULT_CONFIG,
},
}
@@ -21,7 +24,17 @@ export const useLocalConfigStore = defineStore('local_config', {
},
actions: {
set({ path, value }) {
- set(this.prefsStorage, path, value)
+ const definition = LOCAL_DEFAULT_CONFIG_DEFINITIONS[path]
+
+ const finalValue = validateSetting({
+ path,
+ value,
+ definition,
+ throwError: false,
+ defaultState: LOCAL_DEFAULT_CONFIG,
+ })
+
+ set(this.prefsStorage, path, finalValue)
},
setTemporarily({ path, value }) {
set(this.tempStorage, path, value)
diff --git a/src/stores/sync_config.js b/src/stores/sync_config.js
index d4b5ad50a..57deb9c60 100644
--- a/src/stores/sync_config.js
+++ b/src/stores/sync_config.js
@@ -25,8 +25,10 @@ import { useLocalConfigStore } from 'src/stores/local_config.js'
import { storage } from 'src/lib/storage.js'
import {
defaultState as configDefaultState,
- defaultConfigLocal,
- instanceDefaultConfig,
+ validateSetting,
+ INSTANCE_DEFAULT_CONFIG,
+ INSTANCE_DEFAULT_CONFIG_DEFINITIONS,
+ LOCAL_DEFAULT_CONFIG,
LOCAL_ONLY_KEYS,
} from 'src/modules/default_config_state.js'
import { oldDefaultConfigSync } from 'src/modules/old_default_config_state.js'
@@ -488,7 +490,19 @@ export const useSyncConfigStore = defineStore('sync_config', {
`Calling set on depth > 3 (path: ${path}) is not allowed`,
)
}
- set(this.prefsStorage, path, value)
+
+ const definition = INSTANCE_DEFAULT_CONFIG_DEFINITIONS[path.split('.')[1]]
+
+ const finalValue = validateSetting({
+ path: path.split('.')[1],
+ value,
+ definition,
+ throwError: false,
+ defaultState: INSTANCE_DEFAULT_CONFIG,
+ })
+
+ set(this.prefsStorage, path, finalValue)
+
this.prefsStorage._journal = [
...this.prefsStorage._journal,
{ operation: 'set', path, args: [value], timestamp: Date.now() },
@@ -750,12 +764,12 @@ export const useSyncConfigStore = defineStore('sync_config', {
? (tempPrefs[k] ??
localPrefs[k] ??
instancePrefs[k] ??
- defaultConfigLocal[k])
+ LOCAL_DEFAULT_CONFIG[k])
: (tempPrefs[k] ??
localPrefs[k] ??
value ??
instancePrefs[k] ??
- instanceDefaultConfig[k]),
+ INSTANCE_DEFAULT_CONFIG[k]),
]),
)
return result
@@ -766,8 +780,8 @@ export const useSyncConfigStore = defineStore('sync_config', {
Object.entries(state.prefsStorage.simple).map(([k, value]) => [
k,
LOCAL_ONLY_KEYS.has(k)
- ? (instancePrefs[k] ?? defaultConfigLocal[k])
- : (instancePrefs[k] ?? instanceDefaultConfig[k]),
+ ? (instancePrefs[k] ?? LOCAL_DEFAULT_CONFIG[k])
+ : (instancePrefs[k] ?? INSTANCE_DEFAULT_CONFIG[k]),
]),
)
return result
diff --git a/src/sw.js b/src/sw.js
index b7c551480..1e7abd3de 100644
--- a/src/sw.js
+++ b/src/sw.js
@@ -5,7 +5,7 @@ import 'virtual:pleroma-fe/service_worker_env'
import { createI18n } from 'vue-i18n'
import { storage } from 'src/lib/storage.js'
-import { instanceDefaultConfig } from 'src/modules/default_config_state.js'
+import { INSTANCE_DEFAULT_CONFIG } from 'src/modules/default_config_state.js'
import { parseNotification } from 'src/services/entity_normalizer/entity_normalizer.service.js'
import { prepareNotificationObject } from 'src/services/notification_utils/notification_utils.js'
import { cacheKey, emojiCacheKey, shouldCache } from 'src/services/sw/sw.js'
@@ -40,7 +40,7 @@ const setSettings = async () => {
i18n.locale = locale
const notificationsNativeArray = Object.entries(
piniaState.prefsStorage.simple.notificationNative ||
- instanceDefaultConfig.notificationNative,
+ INSTANCE_DEFAULT_CONFIG.notificationNative,
)
state.webPushAlwaysShowNotifications =
piniaState.prefsStorage.simple.webPushAlwaysShowNotifications