restructure settings definitions
This commit is contained in:
parent
694a1f0103
commit
a461068e40
9 changed files with 432 additions and 139 deletions
|
|
@ -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 {
|
||||||
instanceDefaultConfigDefinitions,
|
INSTANCE_DEFAULT_CONFIG_DEFINITIONS,
|
||||||
instanceIdentityDefaultDefinitions,
|
INSTANCE_IDENTITY_DEFAULT_DEFINITIONS,
|
||||||
} from 'src/modules/default_config_state.js'
|
} from 'src/modules/default_config_state.js'
|
||||||
|
|
||||||
let staticInitialResults = null
|
let staticInitialResults = null
|
||||||
|
|
@ -83,7 +83,7 @@ const getInstanceConfig = async ({ store }) => {
|
||||||
const res = await preloadFetch('/api/v1/instance')
|
const res = await preloadFetch('/api/v1/instance')
|
||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
const data = await res.json()
|
const data = await res.json()
|
||||||
const textlimit = data.max_toot_chars
|
const textLimit = data.max_toot_chars
|
||||||
const vapidPublicKey = data.pleroma.vapid_public_key
|
const vapidPublicKey = data.pleroma.vapid_public_key
|
||||||
|
|
||||||
useInstanceCapabilitiesStore().set(
|
useInstanceCapabilitiesStore().set(
|
||||||
|
|
@ -91,8 +91,8 @@ const getInstanceConfig = async ({ store }) => {
|
||||||
data.pleroma,
|
data.pleroma,
|
||||||
)
|
)
|
||||||
useInstanceStore().set({
|
useInstanceStore().set({
|
||||||
path: 'textlimit',
|
path: 'limits.textLimit',
|
||||||
value: textlimit,
|
value: textLimit,
|
||||||
})
|
})
|
||||||
useInstanceStore().set({
|
useInstanceStore().set({
|
||||||
path: 'accountApprovalRequired',
|
path: 'accountApprovalRequired',
|
||||||
|
|
@ -169,22 +169,19 @@ const setSettings = async ({ apiConfig, staticConfig, store }) => {
|
||||||
config = Object.assign({}, staticConfig, apiConfig)
|
config = Object.assign({}, staticConfig, apiConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
const copyInstanceOption = ({ source, definition = { required: true }, destination }) => {
|
Object.keys(INSTANCE_IDENTITY_DEFAULT_DEFINITIONS).forEach((source) =>
|
||||||
const value = config[source]
|
useInstanceStore().set({
|
||||||
let { required, type, default: defaultValue } = definition
|
value: config[source],
|
||||||
if (type == null && defaultValue != null) type = typeof defaultValue
|
path: `instanceIdentity.${source}`,
|
||||||
if (required && value == null) return
|
}),
|
||||||
if (type != null && typeof value !== type) return
|
)
|
||||||
|
|
||||||
useInstanceStore().set({ path: destination, value })
|
Object.keys(INSTANCE_DEFAULT_CONFIG_DEFINITIONS).forEach((source) =>
|
||||||
}
|
useInstanceStore().set({
|
||||||
|
value: config[source],
|
||||||
Object.entries(instanceIdentityDefaultDefinitions)
|
path: `prefsStorage.${source}`,
|
||||||
.map(([source, definition]) => ({ source, definition, destination: `instanceIdentity.${source}` }))
|
}),
|
||||||
.forEach(copyInstanceOption)
|
)
|
||||||
Object.keys(instanceDefaultConfigDefinitions)
|
|
||||||
.map(([source, definition]) => ({ source, definition, destination: `prefsStorage.${source}` }))
|
|
||||||
.forEach(copyInstanceOption)
|
|
||||||
|
|
||||||
useAuthFlowStore().setInitialStrategy(config.loginMethod)
|
useAuthFlowStore().setInitialStrategy(config.loginMethod)
|
||||||
}
|
}
|
||||||
|
|
@ -194,7 +191,7 @@ const getTOS = async ({ store }) => {
|
||||||
const res = await window.fetch('/static/terms-of-service.html')
|
const res = await window.fetch('/static/terms-of-service.html')
|
||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
const html = await res.text()
|
const html = await res.text()
|
||||||
useInstanceStore().set({ name: 'instanceIdentity.tos', value: html })
|
useInstanceStore().set({ path: 'instanceIdentity.tos', value: html })
|
||||||
} else {
|
} else {
|
||||||
throw res
|
throw res
|
||||||
}
|
}
|
||||||
|
|
@ -543,7 +540,7 @@ const afterStoreSetup = async ({ pinia, store, storageError, i18n }) => {
|
||||||
typeof overrides.target !== 'undefined'
|
typeof overrides.target !== 'undefined'
|
||||||
? overrides.target
|
? overrides.target
|
||||||
: window.location.origin
|
: window.location.origin
|
||||||
useInstanceStore().set({ name: 'server', value: server })
|
useInstanceStore().set({ path: 'server', value: server })
|
||||||
|
|
||||||
await setConfig({ store })
|
await setConfig({ store })
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ const FeaturesPanel = {
|
||||||
'mediaProxyAvailable',
|
'mediaProxyAvailable',
|
||||||
]),
|
]),
|
||||||
...mapState(useInstanceStore, {
|
...mapState(useInstanceStore, {
|
||||||
textlimit: (store) => store.limits.textlimit,
|
textLimit: (store) => store.limits.textLimit,
|
||||||
uploadlimit: (store) =>
|
uploadlimit: (store) =>
|
||||||
fileSizeFormatService.fileSizeFormat(store.limits.uploadlimit),
|
fileSizeFormatService.fileSizeFormat(store.limits.uploadlimit),
|
||||||
}),
|
}),
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@
|
||||||
{{ $t('features_panel.media_proxy') }}
|
{{ $t('features_panel.media_proxy') }}
|
||||||
</li>
|
</li>
|
||||||
<li>{{ $t('features_panel.scope_options') }}</li>
|
<li>{{ $t('features_panel.scope_options') }}</li>
|
||||||
<li>{{ $t('features_panel.text_limit') }} = {{ textlimit }}</li>
|
<li>{{ $t('features_panel.text_limit') }} = {{ textLimit }}</li>
|
||||||
<li>{{ $t('features_panel.upload_limit') }} = {{ uploadlimit.num }} {{ $t('upload.file_size_units.' + uploadlimit.unit) }}</li>
|
<li>{{ $t('features_panel.upload_limit') }} = {{ uploadlimit.num }} {{ $t('upload.file_size_units.' + uploadlimit.unit) }}</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -290,7 +290,7 @@ const PostStatusForm = {
|
||||||
return this.newStatus.spoilerText.length
|
return this.newStatus.spoilerText.length
|
||||||
},
|
},
|
||||||
statusLengthLimit() {
|
statusLengthLimit() {
|
||||||
return useInstanceStore().textlimit
|
return useInstanceStore().limits.textLimit
|
||||||
},
|
},
|
||||||
hasStatusLengthLimit() {
|
hasStatusLengthLimit() {
|
||||||
return this.statusLengthLimit > 0
|
return this.statusLengthLimit > 0
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,19 @@
|
||||||
|
import { get, set } from 'lodash'
|
||||||
|
|
||||||
const browserLocale = (navigator.language || 'en').split('-')[0]
|
const browserLocale = (navigator.language || 'en').split('-')[0]
|
||||||
|
|
||||||
const convertDefinitions = definitions => Object.fromEntries(
|
export const convertDefinitions = (definitions) =>
|
||||||
Object.entries(definitions).map(([k, v]) => [
|
Object.fromEntries(
|
||||||
k,
|
Object.entries(definitions).map(([k, v]) => {
|
||||||
v.default == null ? null : v.default,
|
const defaultValue = v.default ?? null
|
||||||
]),
|
return [k, defaultValue]
|
||||||
)
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
/// 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 instanceIdentityDefaultDefinitions = {
|
export const INSTANCE_IDENTITY_DEFAULT_DEFINITIONS = {
|
||||||
style: {
|
style: {
|
||||||
description: 'Instance default style name',
|
description: 'Instance default style name',
|
||||||
type: 'string',
|
type: 'string',
|
||||||
|
|
@ -110,14 +113,17 @@ export const instanceIdentityDefaultDefinitions = {
|
||||||
required: false,
|
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
|
/// 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 instanceDefaultConfigDefinitions = {
|
export const INSTANCE_DEFAULT_CONFIG_DEFINITIONS = {
|
||||||
expertLevel: {
|
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
|
type: 'number', // not a boolean so we could potentially make multiple levels of expert-ness
|
||||||
default: 0,
|
default: 0,
|
||||||
},
|
},
|
||||||
|
|
@ -133,7 +139,8 @@ export const instanceDefaultConfigDefinitions = {
|
||||||
description: 'Hide shoutbox if present',
|
description: 'Hide shoutbox if present',
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
hideMutedPosts: { // bad name
|
hideMutedPosts: {
|
||||||
|
// bad name
|
||||||
description: 'Hide posts of muted users entirely',
|
description: 'Hide posts of muted users entirely',
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
|
|
@ -205,7 +212,8 @@ export const instanceDefaultConfigDefinitions = {
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
autohideFloatingPostButton: {
|
autohideFloatingPostButton: {
|
||||||
description: 'Automatically hide mobile "new post" button when scrolling down',
|
description:
|
||||||
|
'Automatically hide mobile "new post" button when scrolling down',
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
stopGifs: {
|
stopGifs: {
|
||||||
|
|
@ -400,7 +408,8 @@ export const instanceDefaultConfigDefinitions = {
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
mentionLinkFadeDomain: {
|
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,
|
default: true,
|
||||||
},
|
},
|
||||||
mentionLinkShowYous: {
|
mentionLinkShowYous: {
|
||||||
|
|
@ -448,7 +457,8 @@ export const instanceDefaultConfigDefinitions = {
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
showExtraNotifications: {
|
showExtraNotifications: {
|
||||||
description: 'Show extra notifications (chats, announcements etc) in notification panel',
|
description:
|
||||||
|
'Show extra notifications (chats, announcements etc) in notification panel',
|
||||||
default: true,
|
default: true,
|
||||||
},
|
},
|
||||||
showExtraNotificationsTip: {
|
showExtraNotificationsTip: {
|
||||||
|
|
@ -507,41 +517,141 @@ export const instanceDefaultConfigDefinitions = {
|
||||||
description: 'Use 24h time format',
|
description: 'Use 24h time format',
|
||||||
default: '24h',
|
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 = {
|
export const LOCAL_DEFAULT_CONFIG_DEFINITIONS = {
|
||||||
hideAttachments: false,
|
// TODO these two used to be separate but since separation feature got broken it doesn't matter
|
||||||
hideAttachmentsInConv: false,
|
hideAttachments: {
|
||||||
hideNsfw: true,
|
description: 'Hide attachments in timeline',
|
||||||
useOneClickNsfw: false,
|
default: false,
|
||||||
preloadImage: true,
|
},
|
||||||
postContentType: 'text/plain',
|
hideAttachmentsInConv: {
|
||||||
sidebarRight: false,
|
description: 'Hide attachments in coversation',
|
||||||
sidebarColumnWidth: '25rem',
|
default: false,
|
||||||
contentColumnWidth: '45rem',
|
},
|
||||||
notifsColumnWidth: '25rem',
|
hideNsfw: {
|
||||||
themeEditorMinWidth: '0rem',
|
description: 'Hide nsfw posts',
|
||||||
emojiReactionsScale: 0.5,
|
default: true,
|
||||||
textSize: '1rem',
|
},
|
||||||
emojiSize: '2.2rem',
|
useOneClickNsfw: {
|
||||||
navbarSize: '3.5rem',
|
description: 'Open NSFW images directly in media modal',
|
||||||
panelHeaderSize: '3.2rem',
|
default: false,
|
||||||
navbarColumnStretch: false,
|
},
|
||||||
mentionLinkDisplay: 'short',
|
preloadImage: {
|
||||||
alwaysUseJpeg: false,
|
description: 'Preload images for NSFW',
|
||||||
imageCompression: true,
|
default: true,
|
||||||
useStreamingApi: false,
|
},
|
||||||
underlay: 'none',
|
postContentType: {
|
||||||
fontInterface: undefined,
|
description: 'Default post content type',
|
||||||
fontInput: undefined,
|
default: 'text/plain',
|
||||||
fontPosts: undefined,
|
},
|
||||||
fontMonospace: undefined,
|
sidebarRight: {
|
||||||
themeDebug: false, // debug mode that uses computed backgrounds instead of real ones to debug contrast functions
|
description: 'Reverse order of columns',
|
||||||
forceThemeRecompilation: false, // flag that forces recompilation on boot even if cache exists
|
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) =>
|
export const makeUndefined = (c) =>
|
||||||
Object.fromEntries(Object.keys(c).map((key) => [key, undefined]))
|
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.
|
/// make sense to be overriden on a instance-wide level.
|
||||||
export const defaultState = {
|
export const defaultState = {
|
||||||
// Set these to undefined so it does not interfere with default settings check
|
// Set these to undefined so it does not interfere with default settings check
|
||||||
...makeUndefined(instanceDefaultConfig),
|
...makeUndefined(INSTANCE_DEFAULT_CONFIG),
|
||||||
...makeUndefined(defaultConfigLocal),
|
...makeUndefined(LOCAL_DEFAULT_CONFIG),
|
||||||
// If there are any configurations that does not make sense to
|
// If there are any configurations that does not make sense to
|
||||||
// have instance-wide default, put it here and explain why.
|
// have instance-wide default, put it here and explain why.
|
||||||
|
|
||||||
|
|
@ -572,3 +682,53 @@ export const defaultState = {
|
||||||
palette: null,
|
palette: null,
|
||||||
paletteCustomData: 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
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,41 +1,146 @@
|
||||||
import { get, set } from 'lodash'
|
import { get, set } from 'lodash'
|
||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
|
|
||||||
import { instanceDefaultProperties } from '../modules/config.js'
|
|
||||||
import {
|
import {
|
||||||
defaultConfigLocal,
|
convertDefinitions,
|
||||||
instanceDefaultConfig,
|
INSTANCE_DEFAULT_CONFIG,
|
||||||
instanceIdentityDefault,
|
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'
|
} from '../modules/default_config_state.js'
|
||||||
import apiService from '../services/api/api.service.js'
|
import apiService from '../services/api/api.service.js'
|
||||||
|
|
||||||
import { useInterfaceStore } from 'src/stores/interface.js'
|
import { useInterfaceStore } from 'src/stores/interface.js'
|
||||||
|
|
||||||
import { ensureFinalFallback } from 'src/i18n/languages.js'
|
|
||||||
|
|
||||||
const REMOTE_INTERACTION_URL = '/main/ostatus'
|
const REMOTE_INTERACTION_URL = '/main/ostatus'
|
||||||
|
|
||||||
const defaultState = {
|
const ROOT_STATE_DEFINITIONS = {
|
||||||
name: 'Pleroma FE',
|
name: {
|
||||||
registrationOpen: true,
|
type: 'string',
|
||||||
server: 'http://localhost:4040/',
|
default: 'PleromaFE',
|
||||||
textlimit: 5000,
|
},
|
||||||
privateMode: false,
|
registrationOpen: {
|
||||||
federating: true,
|
required: true,
|
||||||
federationPolicy: null,
|
type: 'boolean',
|
||||||
themesIndex: null,
|
},
|
||||||
stylesIndex: null,
|
server: {
|
||||||
palettesIndex: null,
|
description: 'Server URL',
|
||||||
themeData: null, // used for theme editor v2
|
required: true,
|
||||||
vapidPublicKey: null,
|
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
|
// Stuff from static/config.json
|
||||||
loginMethod: 'password',
|
loginMethod: {
|
||||||
disableUpdateNotification: false,
|
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
|
// Instance-wide configurations that should not be changed by individual users
|
||||||
instanceIdentity: {
|
instanceIdentity: {
|
||||||
...instanceIdentityDefault,
|
...INSTANCE_IDENTITY_DEFAULT,
|
||||||
},
|
},
|
||||||
|
|
||||||
limits: {
|
limits: {
|
||||||
|
|
@ -44,6 +149,7 @@ const defaultState = {
|
||||||
backgroundlimit: null,
|
backgroundlimit: null,
|
||||||
uploadlimit: null,
|
uploadlimit: null,
|
||||||
fieldsLimits: null,
|
fieldsLimits: null,
|
||||||
|
textLimit: null,
|
||||||
pollLimits: {
|
pollLimits: {
|
||||||
max_options: 4,
|
max_options: 4,
|
||||||
max_option_chars: 255,
|
max_option_chars: 255,
|
||||||
|
|
@ -54,50 +160,53 @@ const defaultState = {
|
||||||
|
|
||||||
// Instance admins can override default settings for the whole instance
|
// Instance admins can override default settings for the whole instance
|
||||||
prefsStorage: {
|
prefsStorage: {
|
||||||
...instanceDefaultConfig,
|
...INSTANCE_DEFAULT_CONFIG,
|
||||||
...defaultConfigLocal,
|
...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', {
|
export const useInstanceStore = defineStore('instance', {
|
||||||
state: () => ({ ...defaultState }),
|
state: () => ({ ...DEFAULT_STATE }),
|
||||||
getters: {
|
getters: {
|
||||||
instanceDefaultConfig(state) {
|
|
||||||
return instanceDefaultProperties
|
|
||||||
.map((key) => [key, state[key]])
|
|
||||||
.reduce((acc, [key, value]) => ({ ...acc, [key]: value }), {})
|
|
||||||
},
|
|
||||||
instanceDomain(state) {
|
instanceDomain(state) {
|
||||||
return new URL(this.server).hostname
|
return new URL(this.server).hostname
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
set({ path, name, value }) {
|
set({ path, value }) {
|
||||||
if (get(defaultState, path ?? name) === undefined)
|
let definition
|
||||||
console.error(
|
const pathArray = path.split('.')
|
||||||
`Unknown instance option ${path ?? name}, value: ${value}`,
|
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() {
|
async getKnownDomains() {
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
|
|
@ -4,14 +4,17 @@ import { toRaw } from 'vue'
|
||||||
|
|
||||||
import { useInstanceStore } from 'src/stores/instance'
|
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 = {
|
export const defaultState = {
|
||||||
prefsStorage: {
|
prefsStorage: {
|
||||||
...configDefaultState,
|
...LOCAL_DEFAULT_CONFIG,
|
||||||
},
|
},
|
||||||
tempStorage: {
|
tempStorage: {
|
||||||
...configDefaultState,
|
...LOCAL_DEFAULT_CONFIG,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -21,7 +24,17 @@ export const useLocalConfigStore = defineStore('local_config', {
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
set({ path, value }) {
|
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 }) {
|
setTemporarily({ path, value }) {
|
||||||
set(this.tempStorage, path, value)
|
set(this.tempStorage, path, value)
|
||||||
|
|
|
||||||
|
|
@ -25,8 +25,10 @@ import { useLocalConfigStore } from 'src/stores/local_config.js'
|
||||||
import { storage } from 'src/lib/storage.js'
|
import { storage } from 'src/lib/storage.js'
|
||||||
import {
|
import {
|
||||||
defaultState as configDefaultState,
|
defaultState as configDefaultState,
|
||||||
defaultConfigLocal,
|
validateSetting,
|
||||||
instanceDefaultConfig,
|
INSTANCE_DEFAULT_CONFIG,
|
||||||
|
INSTANCE_DEFAULT_CONFIG_DEFINITIONS,
|
||||||
|
LOCAL_DEFAULT_CONFIG,
|
||||||
LOCAL_ONLY_KEYS,
|
LOCAL_ONLY_KEYS,
|
||||||
} from 'src/modules/default_config_state.js'
|
} from 'src/modules/default_config_state.js'
|
||||||
import { oldDefaultConfigSync } from 'src/modules/old_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`,
|
`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 = [
|
||||||
...this.prefsStorage._journal,
|
...this.prefsStorage._journal,
|
||||||
{ operation: 'set', path, args: [value], timestamp: Date.now() },
|
{ operation: 'set', path, args: [value], timestamp: Date.now() },
|
||||||
|
|
@ -750,12 +764,12 @@ export const useSyncConfigStore = defineStore('sync_config', {
|
||||||
? (tempPrefs[k] ??
|
? (tempPrefs[k] ??
|
||||||
localPrefs[k] ??
|
localPrefs[k] ??
|
||||||
instancePrefs[k] ??
|
instancePrefs[k] ??
|
||||||
defaultConfigLocal[k])
|
LOCAL_DEFAULT_CONFIG[k])
|
||||||
: (tempPrefs[k] ??
|
: (tempPrefs[k] ??
|
||||||
localPrefs[k] ??
|
localPrefs[k] ??
|
||||||
value ??
|
value ??
|
||||||
instancePrefs[k] ??
|
instancePrefs[k] ??
|
||||||
instanceDefaultConfig[k]),
|
INSTANCE_DEFAULT_CONFIG[k]),
|
||||||
]),
|
]),
|
||||||
)
|
)
|
||||||
return result
|
return result
|
||||||
|
|
@ -766,8 +780,8 @@ export const useSyncConfigStore = defineStore('sync_config', {
|
||||||
Object.entries(state.prefsStorage.simple).map(([k, value]) => [
|
Object.entries(state.prefsStorage.simple).map(([k, value]) => [
|
||||||
k,
|
k,
|
||||||
LOCAL_ONLY_KEYS.has(k)
|
LOCAL_ONLY_KEYS.has(k)
|
||||||
? (instancePrefs[k] ?? defaultConfigLocal[k])
|
? (instancePrefs[k] ?? LOCAL_DEFAULT_CONFIG[k])
|
||||||
: (instancePrefs[k] ?? instanceDefaultConfig[k]),
|
: (instancePrefs[k] ?? INSTANCE_DEFAULT_CONFIG[k]),
|
||||||
]),
|
]),
|
||||||
)
|
)
|
||||||
return result
|
return result
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import 'virtual:pleroma-fe/service_worker_env'
|
||||||
import { createI18n } from 'vue-i18n'
|
import { createI18n } from 'vue-i18n'
|
||||||
|
|
||||||
import { storage } from 'src/lib/storage.js'
|
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 { parseNotification } from 'src/services/entity_normalizer/entity_normalizer.service.js'
|
||||||
import { prepareNotificationObject } from 'src/services/notification_utils/notification_utils.js'
|
import { prepareNotificationObject } from 'src/services/notification_utils/notification_utils.js'
|
||||||
import { cacheKey, emojiCacheKey, shouldCache } from 'src/services/sw/sw.js'
|
import { cacheKey, emojiCacheKey, shouldCache } from 'src/services/sw/sw.js'
|
||||||
|
|
@ -40,7 +40,7 @@ const setSettings = async () => {
|
||||||
i18n.locale = locale
|
i18n.locale = locale
|
||||||
const notificationsNativeArray = Object.entries(
|
const notificationsNativeArray = Object.entries(
|
||||||
piniaState.prefsStorage.simple.notificationNative ||
|
piniaState.prefsStorage.simple.notificationNative ||
|
||||||
instanceDefaultConfig.notificationNative,
|
INSTANCE_DEFAULT_CONFIG.notificationNative,
|
||||||
)
|
)
|
||||||
state.webPushAlwaysShowNotifications =
|
state.webPushAlwaysShowNotifications =
|
||||||
piniaState.prefsStorage.simple.webPushAlwaysShowNotifications
|
piniaState.prefsStorage.simple.webPushAlwaysShowNotifications
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue