diff --git a/src/App.js b/src/App.js index 2af10cc8b..bfdeb2be4 100644 --- a/src/App.js +++ b/src/App.js @@ -22,6 +22,7 @@ import UserReportingModal from './components/user_reporting_modal/user_reporting import WhoToFollowPanel from './components/who_to_follow_panel/who_to_follow_panel.vue' import { getOrCreateServiceWorker } from './services/sw/sw' import { windowHeight, windowWidth } from './services/window_utils/window_utils' +import { useInstanceStore } from './stores/instance' import { useInterfaceStore } from './stores/interface' import { useShoutStore } from './stores/shout' @@ -135,11 +136,6 @@ export default { userBackground() { return this.currentUser.background_image }, - instanceBackground() { - return this.mergedConfig.hideInstanceWallpaper - ? null - : this.$store.state.instance.background - }, background() { return this.userBackground || this.instanceBackground }, @@ -153,16 +149,6 @@ export default { shout() { return useShoutStore().joined }, - suggestionsEnabled() { - return this.$store.state.instance.suggestionsEnabled - }, - showInstanceSpecificPanel() { - return ( - this.$store.state.instance.showInstanceSpecificPanel && - !this.$store.getters.mergedConfig.hideISP && - this.$store.state.instance.instanceSpecificPanelContent - ) - }, isChats() { return this.$route.name === 'chat' || this.$route.name === 'chats' }, @@ -177,21 +163,12 @@ export default { this.layoutType === 'mobile' ) }, - showFeaturesPanel() { - return this.$store.state.instance.showFeaturesPanel - }, - editingAvailable() { - return this.$store.state.instance.editingAvailable - }, shoutboxPosition() { return this.$store.getters.mergedConfig.alwaysShowNewPostButton || false }, layoutType() { return useInterfaceStore().layoutType }, - privateMode() { - return this.$store.state.instance.private - }, reverseLayout() { const { thirdColumnMode, sidebarRight: reverseSetting } = this.$store.getters.mergedConfig @@ -214,8 +191,22 @@ export default { }, ...mapGetters(['mergedConfig']), ...mapState(useServerSideStorageStore, { - hideShoutbox: (store) => store.prefsStorage.simple.hideShoutbox, + hideShoutbox: (store) => store.mergedConfig.hideShoutbox, }), + ...mapState(useInstanceStore, { + instanceBackground: (store) => + this.mergedConfig.hideInstanceWallpaper ? null : store.background, + showInstanceSpecificPanel: (store) => + store.showInstanceSpecificPanel && + !this.$store.getters.mergedConfig.hideISP && + store.instanceSpecificPanelContent, + }), + ...mapState(useInstanceStore, [ + 'editingAvailable', + 'showFeaturesPanel', + 'private', + 'suggestionsEnabled', + ]), }, methods: { resizeHandler() { diff --git a/src/boot/after_store.js b/src/boot/after_store.js index 1a2be5bd7..48dc42bc1 100644 --- a/src/boot/after_store.js +++ b/src/boot/after_store.js @@ -1,6 +1,7 @@ /* global process */ import vClickOutside from 'click-outside-vue3' +import { get, set } from 'lodash' import { createApp } from 'vue' import { createRouter, createWebHistory } from 'vue-router' import VueVirtualScroller from 'vue-virtual-scroller' @@ -22,6 +23,7 @@ import { import { useAnnouncementsStore } from 'src/stores/announcements' import { useAuthFlowStore } from 'src/stores/auth_flow' import { useI18nStore } from 'src/stores/i18n' +import { useInstanceStore } from 'src/stores/instance' import { useInterfaceStore } from 'src/stores/interface' import { useOAuthStore } from 'src/stores/oauth' import App from '../App.vue' @@ -78,30 +80,30 @@ const getInstanceConfig = async ({ store }) => { const textlimit = data.max_toot_chars const vapidPublicKey = data.pleroma.vapid_public_key - store.dispatch('setInstanceOption', { - name: 'pleromaExtensionsAvailable', + useInstanceStore().set({ + path: 'featureSet.pleromaExtensionsAvailable', value: data.pleroma, }) - store.dispatch('setInstanceOption', { - name: 'textlimit', + useInstanceStore().set({ + path: 'textlimit', value: textlimit, }) - store.dispatch('setInstanceOption', { - name: 'accountApprovalRequired', + useInstanceStore().set({ + path: 'accountApprovalRequired', value: data.approval_required, }) - store.dispatch('setInstanceOption', { - name: 'birthdayRequired', + useInstanceStore().set({ + path: 'birthdayRequired', value: !!data.pleroma?.metadata.birthday_required, }) - store.dispatch('setInstanceOption', { - name: 'birthdayMinAge', + useInstanceStore().set({ + path: 'birthdayMinAge', value: data.pleroma?.metadata.birthday_min_age || 0, }) if (vapidPublicKey) { - store.dispatch('setInstanceOption', { - name: 'vapidPublicKey', + useInstanceStore().set({ + path: 'vapidPublicKey', value: vapidPublicKey, }) } @@ -156,19 +158,32 @@ const setSettings = async ({ apiConfig, staticConfig, store }) => { let config = {} if (overrides.staticConfigPreference && env === 'development') { console.warn('OVERRIDING API CONFIG WITH STATIC CONFIG') - config = Object.assign({}, apiConfig, staticConfig) + config = { ...apiConfig, ...staticConfig } } else { - config = Object.assign({}, staticConfig, apiConfig) + config = { ...staticConfig, ...apiConfig } } + console.trace(config) - const copyInstanceOption = (name) => { - if (typeof config[name] !== 'undefined') { - store.dispatch('setInstanceOption', { name, value: config[name] }) + const copyInstanceIdentityOption = (path) => { + if (get(config, path) !== undefined) { + useInstanceStore().set({ + path: `instanceIdentity.${path}`, + value: get(config, path), + }) } } - Object.keys(staticOrApiConfigDefault).forEach(copyInstanceOption) - Object.keys(instanceDefaultConfig).forEach(copyInstanceOption) + const copyInstancePrefOption = (path) => { + if (get(config, path) !== undefined) { + useInstanceStore().set({ + path: `prefsStorage.${path}`, + value: get(config, path), + }) + } + } + + Object.keys(staticOrApiConfigDefault).forEach(copyInstanceIdentityOption) + Object.keys(instanceDefaultConfig).forEach(copyInstancePrefOption) useAuthFlowStore().setInitialStrategy(config.loginMethod) } @@ -178,7 +193,7 @@ const getTOS = async ({ store }) => { const res = await window.fetch('/static/terms-of-service.html') if (res.ok) { const html = await res.text() - store.dispatch('setInstanceOption', { name: 'tos', value: html }) + useInstanceStore().set({ path: 'tos', value: html }) } else { throw res } @@ -192,8 +207,8 @@ const getInstancePanel = async ({ store }) => { const res = await preloadFetch('/instance/panel.html') if (res.ok) { const html = await res.text() - store.dispatch('setInstanceOption', { - name: 'instanceSpecificPanelContent', + useInstanceStore().set({ + path: 'instanceSpecificPanelContent', value: html, }) } else { @@ -227,7 +242,7 @@ const getStickers = async ({ store }) => { ).sort((a, b) => { return a.meta.title.localeCompare(b.meta.title) }) - store.dispatch('setInstanceOption', { name: 'stickers', value: stickers }) + useInstanceStore().set({ path: 'stickers', value: stickers }) } else { throw res } @@ -248,8 +263,8 @@ const getAppSecret = async ({ store }) => { const resolveStaffAccounts = ({ store, accounts }) => { const nicknames = accounts.map((uri) => uri.split('/').pop()) - store.dispatch('setInstanceOption', { - name: 'staffAccounts', + useInstanceStore().set({ + path: 'staffAccounts', value: nicknames, }) } @@ -262,160 +277,160 @@ const getNodeInfo = async ({ store }) => { const data = await res.json() const metadata = data.metadata const features = metadata.features - store.dispatch('setInstanceOption', { - name: 'name', + useInstanceStore().set({ + path: 'name', value: metadata.nodeName, }) - store.dispatch('setInstanceOption', { - name: 'registrationOpen', + useInstanceStore().set({ + path: 'registrationOpen', value: data.openRegistrations, }) - store.dispatch('setInstanceOption', { - name: 'mediaProxyAvailable', + useInstanceStore().set({ + path: 'featureSet.mediaProxyAvailable', value: features.includes('media_proxy'), }) - store.dispatch('setInstanceOption', { - name: 'safeDM', + useInstanceStore().set({ + path: 'featureSet.safeDM', value: features.includes('safe_dm_mentions'), }) - store.dispatch('setInstanceOption', { - name: 'shoutAvailable', + useInstanceStore().set({ + path: 'featureSet.shoutAvailable', value: features.includes('chat'), }) - store.dispatch('setInstanceOption', { - name: 'pleromaChatMessagesAvailable', + useInstanceStore().set({ + path: 'featureSet.pleromaChatMessagesAvailable', value: features.includes('pleroma_chat_messages'), }) - store.dispatch('setInstanceOption', { - name: 'pleromaCustomEmojiReactionsAvailable', + useInstanceStore().set({ + path: 'featureSet.pleromaCustomEmojiReactionsAvailable', value: features.includes('pleroma_custom_emoji_reactions') || features.includes('custom_emoji_reactions'), }) - store.dispatch('setInstanceOption', { - name: 'pleromaBookmarkFoldersAvailable', + useInstanceStore().set({ + path: 'featureSet.pleromaBookmarkFoldersAvailable', value: features.includes('pleroma:bookmark_folders'), }) - store.dispatch('setInstanceOption', { - name: 'gopherAvailable', + useInstanceStore().set({ + path: 'featureSet.gopherAvailable', value: features.includes('gopher'), }) - store.dispatch('setInstanceOption', { - name: 'pollsAvailable', + useInstanceStore().set({ + path: 'featureSet.pollsAvailable', value: features.includes('polls'), }) - store.dispatch('setInstanceOption', { - name: 'editingAvailable', + useInstanceStore().set({ + path: 'featureSet.editingAvailable', value: features.includes('editing'), }) - store.dispatch('setInstanceOption', { - name: 'pollLimits', + useInstanceStore().set({ + path: 'pollLimits', value: metadata.pollLimits, }) - store.dispatch('setInstanceOption', { - name: 'mailerEnabled', + useInstanceStore().set({ + path: 'featureSet.mailerEnabled', value: metadata.mailerEnabled, }) - store.dispatch('setInstanceOption', { - name: 'quotingAvailable', + useInstanceStore().set({ + path: 'featureSet.quotingAvailable', value: features.includes('quote_posting'), }) - store.dispatch('setInstanceOption', { - name: 'groupActorAvailable', + useInstanceStore().set({ + path: 'featureSet.groupActorAvailable', value: features.includes('pleroma:group_actors'), }) - store.dispatch('setInstanceOption', { - name: 'blockExpiration', + useInstanceStore().set({ + path: 'featureSet.blockExpiration', value: features.includes('pleroma:block_expiration'), }) - store.dispatch('setInstanceOption', { - name: 'localBubbleInstances', + useInstanceStore().set({ + path: 'featureSet.localBubbleInstances', value: metadata.localBubbleInstances ?? [], }) const uploadLimits = metadata.uploadLimits - store.dispatch('setInstanceOption', { - name: 'uploadlimit', + useInstanceStore().set({ + path: 'uploadlimit', value: parseInt(uploadLimits.general), }) - store.dispatch('setInstanceOption', { - name: 'avatarlimit', + useInstanceStore().set({ + path: 'avatarlimit', value: parseInt(uploadLimits.avatar), }) - store.dispatch('setInstanceOption', { - name: 'backgroundlimit', + useInstanceStore().set({ + path: 'backgroundlimit', value: parseInt(uploadLimits.background), }) - store.dispatch('setInstanceOption', { - name: 'bannerlimit', + useInstanceStore().set({ + path: 'bannerlimit', value: parseInt(uploadLimits.banner), }) - store.dispatch('setInstanceOption', { - name: 'fieldsLimits', + useInstanceStore().set({ + path: 'fieldsLimits', value: metadata.fieldsLimits, }) - store.dispatch('setInstanceOption', { - name: 'restrictedNicknames', + useInstanceStore().set({ + path: 'restrictedNicknames', value: metadata.restrictedNicknames, }) - store.dispatch('setInstanceOption', { - name: 'postFormats', + useInstanceStore().set({ + path: 'featureSet.postFormats', value: metadata.postFormats, }) const suggestions = metadata.suggestions - store.dispatch('setInstanceOption', { - name: 'suggestionsEnabled', + useInstanceStore().set({ + path: 'featureSet.suggestionsEnabled', value: suggestions.enabled, }) - store.dispatch('setInstanceOption', { - name: 'suggestionsWeb', + useInstanceStore().set({ + path: 'featureSet.suggestionsWeb', value: suggestions.web, }) const software = data.software - store.dispatch('setInstanceOption', { - name: 'backendVersion', + useInstanceStore().set({ + path: 'backendVersion', value: software.version, }) - store.dispatch('setInstanceOption', { - name: 'backendRepository', + useInstanceStore().set({ + path: 'backendRepository', value: software.repository, }) const priv = metadata.private - store.dispatch('setInstanceOption', { name: 'private', value: priv }) + useInstanceStore().set({ path: 'private', value: priv }) const frontendVersion = window.___pleromafe_commit_hash - store.dispatch('setInstanceOption', { - name: 'frontendVersion', + useInstanceStore().set({ + path: 'frontendVersion', value: frontendVersion, }) const federation = metadata.federation - store.dispatch('setInstanceOption', { - name: 'tagPolicyAvailable', + useInstanceStore().set({ + path: 'featureSet.tagPolicyAvailable', value: typeof federation.mrf_policies === 'undefined' ? false : metadata.federation.mrf_policies.includes('TagPolicy'), }) - store.dispatch('setInstanceOption', { - name: 'federationPolicy', + useInstanceStore().set({ + path: 'federationPolicy', value: federation, }) - store.dispatch('setInstanceOption', { - name: 'federating', + useInstanceStore().set({ + path: 'federating', value: typeof federation.enabled === 'undefined' ? true : federation.enabled, }) const accountActivationRequired = metadata.accountActivationRequired - store.dispatch('setInstanceOption', { - name: 'accountActivationRequired', + useInstanceStore().set({ + path: 'accountActivationRequired', value: accountActivationRequired, }) @@ -526,7 +541,7 @@ const afterStoreSetup = async ({ pinia, store, storageError, i18n }) => { typeof overrides.target !== 'undefined' ? overrides.target : window.location.origin - store.dispatch('setInstanceOption', { name: 'server', value: server }) + useInstanceStore().set({ path: 'server', value: server }) await setConfig({ store }) try { diff --git a/src/components/post_status_form/post_status_form.js b/src/components/post_status_form/post_status_form.js index a073a5eb8..781b3214d 100644 --- a/src/components/post_status_form/post_status_form.js +++ b/src/components/post_status_form/post_status_form.js @@ -299,13 +299,6 @@ const PostStatusForm = { isOverLengthLimit() { return this.hasStatusLengthLimit && this.charactersLeft < 0 }, - minimalScopesMode() { - return useServerSideStorageStore().prefsStorage.simple.minimalScopesMode - }, - alwaysShowSubject() { - return useServerSideStorageStore().prefsStorage.simple - .alwaysShowSubjectInput - }, postFormats() { return this.$store.state.instance.postFormats || [] }, @@ -412,6 +405,10 @@ const PostStatusForm = { ...mapState(useInterfaceStore, { mobileLayout: (store) => store.mobileLayout, }), + ...mapState(useServerSideStorageStore, { + minimalScopesMode: (store) => store.mergedConfig.minimalScopesMode, + alwaysShowSubject: (store) => store.mergedConfig.alwaysShowSubjectInput, + }), }, watch: { newStatus: { diff --git a/src/components/settings_modal/helpers/setting.js b/src/components/settings_modal/helpers/setting.js index 06ed9b2f6..86e54caad 100644 --- a/src/components/settings_modal/helpers/setting.js +++ b/src/components/settings_modal/helpers/setting.js @@ -1,5 +1,6 @@ import { cloneDeep, get, isEqual, set } from 'lodash' +import { useInstanceStore } from 'src/stores/instance' import { useServerSideStorageStore } from 'src/stores/serverSideStorage' import DraftButtons from './draft_buttons.vue' import ModifiedIndicator from './modified_indicator.vue' @@ -228,7 +229,7 @@ export default { configSource() { switch (this.realSource) { case 'server-side': - return useServerSideStorageStore().prefsStorage + return useServerSideStorageStore().mergedConfig case 'profile': return this.$store.state.profileConfig case 'admin': @@ -243,36 +244,10 @@ export default { } switch (this.realSource) { case 'server-side': { - return (path, value, operator) => { - const folder = path.split('.')[0] - if (folder === 'collections' || folder === 'objectCollections') { - switch (operator) { - case 'add': - useServerSideStorageStore().addCollectionPreference({ - path, - value, - }) - useServerSideStorageStore().pushServerSideStorage() - break - case 'remove': - useServerSideStorageStore().removeCollectionPreference({ - path, - value, - }) - useServerSideStorageStore().pushServerSideStorage() - break - default: - console.error( - `Unknown server-side collection operator ${operator}, ignoring`, - ) - break - } - } else if (folder === 'simple') { - useServerSideStorageStore().setPreference({ path, value }) - useServerSideStorageStore().pushServerSideStorage() - } else { - console.error(`Unknown server-side folder ${folder}, ignoring`) - } + return (originalPath, value, operator) => { + const path = `simple.${originalPath}` + useServerSideStorageStore().setPreference({ path, value }) + useServerSideStorageStore().pushServerSideStorage() } } case 'profile': @@ -299,10 +274,7 @@ export default { case 'profile': return {} case 'server-side': - return get( - this.$store.getters.defaultConfig, - this.path.split(/\./g).slice(1), - ) + return get(useInstanceStore().prefsStorage, this.path) default: return get(this.$store.getters.defaultConfig, this.path) } diff --git a/src/components/settings_modal/tabs/clutter_tab.vue b/src/components/settings_modal/tabs/clutter_tab.vue index ef230dee0..59e942492 100644 --- a/src/components/settings_modal/tabs/clutter_tab.vue +++ b/src/components/settings_modal/tabs/clutter_tab.vue @@ -6,7 +6,7 @@