Merge branch 'tusooa/everything-instance-default' into 'develop'

Make every configuration option default-overridable by instance admins

See merge request pleroma/pleroma-fe!2175
This commit is contained in:
HJ 2025-10-14 22:25:29 +00:00
commit 30f9b84f08
5 changed files with 156 additions and 218 deletions

View file

@ -0,0 +1 @@
Make every configuration option default-overridable by instance admins

View file

@ -24,6 +24,7 @@ import { useI18nStore } from 'src/stores/i18n'
import { useInterfaceStore } from 'src/stores/interface' import { useInterfaceStore } from 'src/stores/interface'
import { useAnnouncementsStore } from 'src/stores/announcements' import { useAnnouncementsStore } from 'src/stores/announcements'
import { useAuthFlowStore } from 'src/stores/auth_flow' import { useAuthFlowStore } from 'src/stores/auth_flow'
import { staticOrApiConfigDefault, instanceDefaultConfig } from 'src/modules/default_config_state.js'
let staticInitialResults = null let staticInitialResults = null
@ -130,50 +131,15 @@ const setSettings = async ({ apiConfig, staticConfig, store }) => {
} }
const copyInstanceOption = (name) => { const copyInstanceOption = (name) => {
store.dispatch('setInstanceOption', { name, value: config[name] }) if (typeof config[name] !== 'undefined') {
store.dispatch('setInstanceOption', { name, value: config[name] })
}
} }
copyInstanceOption('theme') Object.keys(staticOrApiConfigDefault).forEach(copyInstanceOption)
copyInstanceOption('style') Object.keys(instanceDefaultConfig).forEach(copyInstanceOption)
copyInstanceOption('palette')
copyInstanceOption('embeddedToS')
copyInstanceOption('nsfwCensorImage')
copyInstanceOption('background')
copyInstanceOption('hidePostStats')
copyInstanceOption('hideBotIndication')
copyInstanceOption('hideUserStats')
copyInstanceOption('hideFilteredStatuses')
copyInstanceOption('logo')
store.dispatch('setInstanceOption', {
name: 'logoMask',
value: typeof config.logoMask === 'undefined'
? true
: config.logoMask
})
store.dispatch('setInstanceOption', {
name: 'logoMargin',
value: typeof config.logoMargin === 'undefined'
? 0
: config.logoMargin
})
copyInstanceOption('logoLeft')
useAuthFlowStore().setInitialStrategy(config.loginMethod) useAuthFlowStore().setInitialStrategy(config.loginMethod)
copyInstanceOption('redirectRootNoLogin')
copyInstanceOption('redirectRootLogin')
copyInstanceOption('showInstanceSpecificPanel')
copyInstanceOption('minimalScopesMode')
copyInstanceOption('hideMutedPosts')
copyInstanceOption('collapseMessageWithSubject')
copyInstanceOption('scopeCopy')
copyInstanceOption('subjectLineBehavior')
copyInstanceOption('postContentType')
copyInstanceOption('alwaysShowSubjectInput')
copyInstanceOption('showFeaturesPanel')
copyInstanceOption('hideSitename')
copyInstanceOption('sidebarRight')
} }
const getTOS = async ({ store }) => { const getTOS = async ({ store }) => {

View file

@ -6,7 +6,7 @@ import localeService from '../services/locale/locale.service.js'
import { useI18nStore } from 'src/stores/i18n.js' import { useI18nStore } from 'src/stores/i18n.js'
import { useInterfaceStore } from 'src/stores/interface.js' import { useInterfaceStore } from 'src/stores/interface.js'
import { defaultState } from './default_config_state.js' import { instanceDefaultConfig, defaultState } from './default_config_state.js'
const BACKEND_LANGUAGE_COOKIE_NAME = 'userLanguage' const BACKEND_LANGUAGE_COOKIE_NAME = 'userLanguage'
const APPEARANCE_SETTINGS_KEYS = new Set([ const APPEARANCE_SETTINGS_KEYS = new Set([
@ -38,9 +38,7 @@ export const multiChoiceProperties = [
] ]
// caching the instance default properties // caching the instance default properties
export const instanceDefaultProperties = Object.entries(defaultState) export const instanceDefaultProperties = Object.keys(instanceDefaultConfig)
.filter(([, value]) => value === undefined)
.map(([key]) => key)
const config = { const config = {
state: { ...defaultState }, state: { ...defaultState },

View file

@ -1,45 +1,43 @@
const browserLocale = (window.navigator.language || 'en').split('-')[0] const browserLocale = (window.navigator.language || 'en').split('-')[0]
export const defaultState = { /// Instance config entries provided by static config or pleroma api
expertLevel: 0, // used to track which settings to show and hide /// Put settings here only if it does not make sense for a normal user
/// to override it.
// Theme stuff export const staticOrApiConfigDefault = {
theme: undefined, // Very old theme store, stores preset name, still in use theme: 'pleroma-dark',
// V1
colors: {}, // VERY old theme store, just colors of V1, probably not even used anymore
// V2
customTheme: undefined, // "snapshot", previously was used as actual theme store for V2 so it's still used in case of PleromaFE downgrade event.
customThemeSource: undefined, // "source", stores original theme data
// V3
style: null,
styleCustomData: null,
palette: null, palette: null,
paletteCustomData: null, style: null,
themeDebug: false, // debug mode that uses computed backgrounds instead of real ones to debug contrast functions defaultAvatar: '/images/avi.png',
forceThemeRecompilation: false, // flag that forces recompilation on boot even if cache exists defaultBanner: '/images/banner.png',
theme3hacks: { // Hacks, user overrides that are independent of theme used background: '/static/aurora_borealis.jpg',
underlay: 'none', embeddedToS: true,
fonts: { logo: '/static/logo.svg',
interface: undefined, logoMargin: '.2em',
input: undefined, logoMask: true,
post: undefined, logoLeft: false,
monospace: undefined redirectRootLogin: '/main/friends',
} redirectRootNoLogin: '/main/all',
}, hideSitename: false,
nsfwCensorImage: undefined,
showFeaturesPanel: true,
showInstanceSpecificPanel: false,
}
/// 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 instanceDefaultConfig = {
expertLevel: 0, // used to track which settings to show and hide
hideISP: false, hideISP: false,
hideInstanceWallpaper: false, hideInstanceWallpaper: false,
hideShoutbox: false, hideShoutbox: false,
// bad name: actually hides posts of muted USERS // bad name: actually hides posts of muted USERS
hideMutedPosts: undefined, // instance default hideMutedPosts: false,
hideMutedThreads: undefined, // instance default hideMutedThreads: true,
hideWordFilteredPosts: undefined, // instance default hideWordFilteredPosts: false,
muteBotStatuses: undefined, // instance default muteBotStatuses: false,
muteSensitiveStatuses: undefined, // instance default muteSensitiveStatuses: false,
collapseMessageWithSubject: undefined, // instance default collapseMessageWithSubject: false,
padEmoji: true, padEmoji: true,
hideAttachments: false, hideAttachments: false,
hideAttachmentsInConv: false, hideAttachmentsInConv: false,
@ -50,6 +48,9 @@ export const defaultState = {
preloadImage: true, preloadImage: true,
loopVideo: true, loopVideo: true,
loopVideoSilentOnly: true, loopVideoSilentOnly: true,
/// This is not the streaming API configuration, but rather an option
/// for automatically loading new posts into the timeline without
/// the user clicking the Show New button.
streaming: false, streaming: false,
emojiReactionsOnTimeline: true, emojiReactionsOnTimeline: true,
alwaysShowNewPostButton: false, alwaysShowNewPostButton: false,
@ -86,39 +87,37 @@ export const defaultState = {
}, },
webPushNotifications: false, webPushNotifications: false,
webPushAlwaysShowNotifications: false, webPushAlwaysShowNotifications: false,
muteWords: [],
highlight: {},
interfaceLanguage: browserLocale, interfaceLanguage: browserLocale,
hideScopeNotice: false, hideScopeNotice: false,
useStreamingApi: false, useStreamingApi: false,
sidebarRight: undefined, // instance default sidebarRight: false,
scopeCopy: undefined, // instance default scopeCopy: true,
subjectLineBehavior: undefined, // instance default subjectLineBehavior: 'email',
alwaysShowSubjectInput: undefined, // instance default alwaysShowSubjectInput: true,
postContentType: undefined, // instance default postContentType: 'text/plain',
minimalScopesMode: undefined, // instance default minimalScopesMode: false,
// This hides statuses filtered via a word filter // This hides statuses filtered via a word filter
hideFilteredStatuses: undefined, // instance default hideFilteredStatuses: false,
// Confirmations // Confirmations
modalOnRepeat: undefined, // instance default modalOnRepeat: false,
modalOnUnfollow: undefined, // instance default modalOnUnfollow: false,
modalOnBlock: undefined, // instance default modalOnBlock: true,
modalOnMute: undefined, // instance default modalOnMute: false,
modalOnMuteConversation: undefined, // instance default modalOnMuteConversation: false,
modalOnMuteDomain: undefined, // instance default modalOnMuteDomain: true,
modalOnDelete: undefined, // instance default modalOnDelete: true,
modalOnLogout: undefined, // instance default modalOnLogout: true,
modalOnApproveFollow: undefined, // instance default modalOnApproveFollow: false,
modalOnDenyFollow: undefined, // instance default modalOnDenyFollow: false,
modalOnRemoveUserFromFollowers: undefined, // instance default modalOnRemoveUserFromFollowers: false,
// Expiry confirmations/default actions // Expiry confirmations/default actions
onMuteDefaultAction: 'ask', onMuteDefaultAction: 'ask',
onBlockDefaultAction: 'ask', onBlockDefaultAction: 'ask',
modalMobileCenter: undefined, modalMobileCenter: false,
playVideosInModal: false, playVideosInModal: false,
useOneClickNsfw: false, useOneClickNsfw: false,
useContainFit: true, useContainFit: true,
@ -131,45 +130,93 @@ export const defaultState = {
sidebarColumnWidth: '25rem', sidebarColumnWidth: '25rem',
contentColumnWidth: '45rem', contentColumnWidth: '45rem',
notifsColumnWidth: '25rem', notifsColumnWidth: '25rem',
themeEditorMinWidth: undefined, // instance default themeEditorMinWidth: '0rem',
emojiReactionsScale: undefined, emojiReactionsScale: 0.5,
textSize: undefined, // instance default textSize: '1rem',
emojiSize: undefined, // instance default emojiSize: '2.2rem',
navbarSize: undefined, // instance default navbarSize: '3.5rem',
panelHeaderSize: undefined, // instance default panelHeaderSize: '3.2rem',
forcedRoundness: undefined, // instance default forcedRoundness: -1,
navbarColumnStretch: false, navbarColumnStretch: false,
greentext: undefined, // instance default greentext: false,
mentionLinkDisplay: undefined, // instance default mentionLinkDisplay: 'short',
mentionLinkShowTooltip: undefined, // instance default mentionLinkShowTooltip: true,
mentionLinkShowAvatar: undefined, // instance default mentionLinkShowAvatar: false,
mentionLinkFadeDomain: undefined, // instance default mentionLinkFadeDomain: true,
mentionLinkShowYous: undefined, // instance default mentionLinkShowYous: false,
mentionLinkBoldenYou: undefined, // instance default mentionLinkBoldenYou: true,
hidePostStats: undefined, // instance default hidePostStats: false,
hideBotIndication: undefined, // instance default hideBotIndication: false,
hideUserStats: undefined, // instance default hideUserStats: false,
virtualScrolling: undefined, // instance default virtualScrolling: true,
sensitiveByDefault: undefined, // instance default sensitiveByDefault: false,
conversationDisplay: undefined, // instance default conversationDisplay: 'linear',
conversationTreeAdvanced: undefined, // instance default conversationTreeAdvanced: false,
conversationOtherRepliesButton: undefined, // instance default conversationOtherRepliesButton: 'below',
conversationTreeFadeAncestors: undefined, // instance default conversationTreeFadeAncestors: false,
showExtraNotifications: undefined, // instance default showExtraNotifications: true,
showExtraNotificationsTip: undefined, // instance default showExtraNotificationsTip: true,
showChatsInExtraNotifications: undefined, // instance default showChatsInExtraNotifications: true,
showAnnouncementsInExtraNotifications: undefined, // instance default showAnnouncementsInExtraNotifications: true,
showFollowRequestsInExtraNotifications: undefined, // instance default showFollowRequestsInExtraNotifications: true,
maxDepthInThread: undefined, // instance default maxDepthInThread: 6,
autocompleteSelect: undefined, // instance default autocompleteSelect: false,
closingDrawerMarksAsSeen: undefined, // instance default closingDrawerMarksAsSeen: true,
unseenAtTop: undefined, // instance default unseenAtTop: false,
ignoreInactionableSeen: undefined, // instance default ignoreInactionableSeen: false,
unsavedPostAction: undefined, // instance default unsavedPostAction: 'confirm',
autoSaveDraft: undefined, // instance default autoSaveDraft: false,
useAbsoluteTimeFormat: undefined, // instance default useAbsoluteTimeFormat: false,
absoluteTimeFormatMinAge: undefined, // instance default absoluteTimeFormatMinAge: '0d',
absoluteTime12h: undefined, // instance default absoluteTime12h: '24h',
imageCompression: true, imageCompression: true,
alwaysUseJpeg: false alwaysUseJpeg: false
} }
export const makeUndefined = c => Object.fromEntries(Object.keys(c).map(key => [key, undefined]))
/// For properties with special processing or properties that does not
/// 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),
// Special processing
// Theme stuff
theme: undefined, // Very old theme store, stores preset name, still in use
// V1
colors: {}, // VERY old theme store, just colors of V1, probably not even used anymore
// V2
customTheme: undefined, // "snapshot", previously was used as actual theme store for V2 so it's still used in case of PleromaFE downgrade event.
customThemeSource: undefined, // "source", stores original theme data
// V3
style: null,
styleCustomData: null,
palette: null,
paletteCustomData: null,
themeDebug: false, // debug mode that uses computed backgrounds instead of real ones to debug contrast functions
forceThemeRecompilation: false, // flag that forces recompilation on boot even if cache exists
theme3hacks: { // Hacks, user overrides that are independent of theme used
underlay: 'none',
fonts: {
interface: undefined,
input: undefined,
post: undefined,
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.
}

View file

@ -4,6 +4,7 @@ import { ensureFinalFallback } from '../i18n/languages.js'
import { useInterfaceStore } from 'src/stores/interface.js' import { useInterfaceStore } from 'src/stores/interface.js'
// See build/emojis_plugin for more details // See build/emojis_plugin for more details
import { annotationsLoader } from 'virtual:pleroma-fe/emoji-annotations' import { annotationsLoader } from 'virtual:pleroma-fe/emoji-annotations'
import { staticOrApiConfigDefault, instanceDefaultConfig } from './default_config_state.js';
const SORTED_EMOJI_GROUP_IDS = [ const SORTED_EMOJI_GROUP_IDS = [
'smileys-and-emotion', 'smileys-and-emotion',
@ -52,90 +53,15 @@ const defaultState = {
vapidPublicKey: undefined, vapidPublicKey: undefined,
// Stuff from static/config.json // Stuff from static/config.json
alwaysShowSubjectInput: true,
defaultAvatar: '/images/avi.png',
defaultBanner: '/images/banner.png',
background: '/static/aurora_borealis.jpg',
embeddedToS: true,
collapseMessageWithSubject: false,
greentext: false,
mentionLinkDisplay: 'short',
mentionLinkShowTooltip: true,
mentionLinkShowAvatar: false,
mentionLinkFadeDomain: true,
mentionLinkShowYous: false,
mentionLinkBoldenYou: true,
hideFilteredStatuses: false,
// bad name: actually hides posts of muted USERS
hideMutedPosts: false,
hideMutedThreads: true,
hideWordFilteredPosts: false,
hidePostStats: false,
hideBotIndication: false,
hideSitename: false,
hideUserStats: false,
muteBotStatuses: false,
muteSensitiveStatuses: false,
modalOnRepeat: false,
modalOnUnfollow: false,
modalOnBlock: true,
modalOnMute: false,
modalOnMuteConversation: false,
modalOnMuteDomain: true,
modalOnDelete: true,
modalOnLogout: true,
modalOnApproveFollow: false,
modalOnDenyFollow: false,
modalOnRemoveUserFromFollowers: false,
modalMobileCenter: false,
loginMethod: 'password', loginMethod: 'password',
logo: '/static/logo.svg',
logoMargin: '.2em',
logoMask: true,
logoLeft: false,
disableUpdateNotification: false, disableUpdateNotification: false,
minimalScopesMode: false,
nsfwCensorImage: undefined,
postContentType: 'text/plain',
redirectRootLogin: '/main/friends',
redirectRootNoLogin: '/main/all',
scopeCopy: true,
showFeaturesPanel: true,
showInstanceSpecificPanel: false,
sidebarRight: false,
subjectLineBehavior: 'email',
theme: 'pleroma-dark',
palette: null,
style: null,
emojiReactionsScale: 0.5,
textSize: '1rem',
emojiSize: '2.2rem',
navbarSize: '3.5rem',
panelHeaderSize: '3.2rem',
themeEditorMinWidth: '0rem',
forcedRoundness: -1,
fontsOverride: {}, fontsOverride: {},
virtualScrolling: true,
sensitiveByDefault: false, // Instance-wide configurations that should not be changed by individual users
conversationDisplay: 'linear', ...staticOrApiConfigDefault,
conversationTreeAdvanced: false, // Instance admins can override default settings for the whole instance
conversationOtherRepliesButton: 'below', ...instanceDefaultConfig,
conversationTreeFadeAncestors: false,
showExtraNotifications: true,
showExtraNotificationsTip: true,
showChatsInExtraNotifications: true,
showAnnouncementsInExtraNotifications: true,
showFollowRequestsInExtraNotifications: true,
maxDepthInThread: 6,
autocompleteSelect: false,
closingDrawerMarksAsSeen: true,
unseenAtTop: false,
ignoreInactionableSeen: false,
unsavedPostAction: 'confirm',
autoSaveDraft: false,
useAbsoluteTimeFormat: false,
absoluteTimeFormatMinAge: '0d',
absoluteTime12h: '24h',
// Nasty stuff // Nasty stuff
customEmoji: [], customEmoji: [],