separate featureset into instancecapabilites store

This commit is contained in:
Henry Jameson 2026-02-05 00:28:45 +02:00
commit 1e93e0a9c3
40 changed files with 239 additions and 247 deletions

View file

@ -23,6 +23,7 @@ import { getOrCreateServiceWorker } from './services/sw/sw'
import { windowHeight, windowWidth } from './services/window_utils/window_utils'
import { useInstanceStore } from 'src/stores/instance.js'
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
import { useInterfaceStore } from 'src/stores/interface.js'
import { useShoutStore } from 'src/stores/shout.js'
@ -203,13 +204,15 @@ export default {
'layoutType',
]),
...mapState(useInstanceStore, ['styleDataUsed', 'private']),
...mapState(useInstanceCapabilitiesStore, [
'suggestionsEnabled',
'editingAvailable',
]),
...mapState(useInstanceStore, {
background: (store) => store.instanceIdentity.background,
showFeaturesPanel: (store) => store.instanceIdentity.showFeaturesPanel,
showInstanceSpecificPanel: (store) =>
store.instanceIdentity.showInstanceSpecificPanel,
suggestionsEnabled: (store) => store.featureSet.suggestionsEnabled,
editingAvailable: (store) => store.featureSet.editingAvailable,
instanceSpecificPanelContent: (store) =>
store.instanceIdentity.instanceSpecificPanelContent,
}),

View file

@ -30,6 +30,7 @@ import { useAuthFlowStore } from 'src/stores/auth_flow'
import { useEmojiStore } from 'src/stores/emoji.js'
import { useI18nStore } from 'src/stores/i18n'
import { useInstanceStore } from 'src/stores/instance.js'
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
import { useInterfaceStore } from 'src/stores/interface.js'
import { useOAuthStore } from 'src/stores/oauth'
@ -82,10 +83,10 @@ const getInstanceConfig = async ({ store }) => {
const textlimit = data.max_toot_chars
const vapidPublicKey = data.pleroma.vapid_public_key
useInstanceStore().set({
name: 'featureSet.pleromaExtensionsAvailable',
value: data.pleroma,
})
useInstanceCapabilitiesStore().set(
'pleromaExtensionsAvailable',
data.pleroma,
)
useInstanceStore().set({
name: 'textlimit',
value: textlimit,
@ -278,68 +279,68 @@ const getNodeInfo = async ({ store }) => {
path: 'registrationOpen',
value: data.openRegistrations,
})
useInstanceStore().set({
path: 'featureSet.mediaProxyAvailable',
value: features.includes('media_proxy'),
})
useInstanceStore().set({
path: 'featureSet.safeDM',
value: features.includes('safe_dm_mentions'),
})
useInstanceStore().set({
path: 'featureSet.shoutAvailable',
value: features.includes('chat'),
})
useInstanceStore().set({
path: 'featureSet.pleromaChatMessagesAvailable',
value: features.includes('pleroma_chat_messages'),
})
useInstanceStore().set({
path: 'featureSet.pleromaCustomEmojiReactionsAvailable',
value:
features.includes('pleroma_custom_emoji_reactions') ||
useInstanceCapabilitiesStore().set(
'mediaProxyAvailable',
features.includes('media_proxy'),
)
useInstanceCapabilitiesStore().set(
'safeDM',
features.includes('safe_dm_mentions'),
)
useInstanceCapabilitiesStore().set(
'shoutAvailable',
features.includes('chat'),
)
useInstanceCapabilitiesStore().set(
'pleromaChatMessagesAvailable',
features.includes('pleroma_chat_messages'),
)
useInstanceCapabilitiesStore().set(
'pleromaCustomEmojiReactionsAvailable',
features.includes('pleroma_custom_emoji_reactions') ||
features.includes('custom_emoji_reactions'),
})
useInstanceStore().set({
path: 'featureSet.pleromaBookmarkFoldersAvailable',
value: features.includes('pleroma:bookmark_folders'),
})
useInstanceStore().set({
path: 'featureSet.gopherAvailable',
value: features.includes('gopher'),
})
useInstanceStore().set({
path: 'featureSet.pollsAvailable',
value: features.includes('polls'),
})
useInstanceStore().set({
path: 'featureSet.editingAvailable',
value: features.includes('editing'),
})
useInstanceStore().set({
path: 'featureSet.mailerEnabled',
value: metadata.mailerEnabled,
})
useInstanceStore().set({
path: 'featureSet.quotingAvailable',
value: features.includes('quote_posting'),
})
useInstanceStore().set({
path: 'featureSet.groupActorAvailable',
value: features.includes('pleroma:group_actors'),
})
useInstanceStore().set({
path: 'featureSet.blockExpiration',
value: features.includes('pleroma:block_expiration'),
})
)
useInstanceCapabilitiesStore().set(
'pleromaBookmarkFoldersAvailable',
features.includes('pleroma:bookmark_folders'),
)
useInstanceCapabilitiesStore().set(
'gopherAvailable',
features.includes('gopher'),
)
useInstanceCapabilitiesStore().set(
'pollsAvailable',
features.includes('polls'),
)
useInstanceCapabilitiesStore().set(
'editingAvailable',
features.includes('editing'),
)
useInstanceCapabilitiesStore().set(
'mailerEnabled',
metadata.mailerEnabled,
)
useInstanceCapabilitiesStore().set(
'quotingAvailable',
features.includes('quote_posting'),
)
useInstanceCapabilitiesStore().set(
'groupActorAvailable',
features.includes('pleroma:group_actors'),
)
useInstanceCapabilitiesStore().set(
'blockExpiration',
features.includes('pleroma:block_expiration'),
)
useInstanceStore().set({
path: 'localBubbleInstances',
value: metadata.localBubbleInstances ?? [],
})
useInstanceStore().set({
path: 'featureSet.localBubble',
value: (metadata.localBubbleInstances ?? []).length > 0,
})
useInstanceCapabilitiesStore().set(
'localBubble',
(metadata.localBubbleInstances ?? []).length > 0,
)
useInstanceStore().set({
path: 'limits.pollLimits',
@ -347,44 +348,39 @@ const getNodeInfo = async ({ store }) => {
})
const uploadLimits = metadata.uploadLimits
useInstanceStore().set({
name: 'limits.uploadlimit',
path: 'limits.uploadlimit',
value: parseInt(uploadLimits.general),
})
useInstanceStore().set({
name: 'limits.avatarlimit',
path: 'limits.avatarlimit',
value: parseInt(uploadLimits.avatar),
})
useInstanceStore().set({
name: 'limits.backgroundlimit',
path: 'limits.backgroundlimit',
value: parseInt(uploadLimits.background),
})
useInstanceStore().set({
name: 'limits.bannerlimit',
path: 'limits.bannerlimit',
value: parseInt(uploadLimits.banner),
})
useInstanceStore().set({
name: 'limits.fieldsLimits',
path: 'limits.fieldsLimits',
value: metadata.fieldsLimits,
})
useInstanceStore().set({
name: 'restrictedNicknames',
path: 'restrictedNicknames',
value: metadata.restrictedNicknames,
})
useInstanceStore().set({
name: 'featureSet.postFormats',
value: metadata.postFormats,
})
useInstanceCapabilitiesStore().set('postFormats', metadata.postFormats)
const suggestions = metadata.suggestions
useInstanceStore().set({
name: 'featureSet.suggestionsEnabled',
value: suggestions.enabled,
})
useInstanceStore().set({
name: 'featureSet.suggestionsWeb',
value: suggestions.web,
})
useInstanceCapabilitiesStore().set(
'suggestionsEnabled',
suggestions.enabled,
)
// this is unused, why?
useInstanceCapabilitiesStore().set('suggestionsWeb', suggestions.web)
const software = data.software
useInstanceStore().set({
@ -407,27 +403,26 @@ const getNodeInfo = async ({ store }) => {
const federation = metadata.federation
useInstanceStore().set({
name: 'featureSet.tagPolicyAvailable',
value:
typeof federation.mrf_policies === 'undefined'
? false
: metadata.federation.mrf_policies.includes('TagPolicy'),
})
useInstanceCapabilitiesStore().set(
'tagPolicyAvailable',
typeof federation.mrf_policies === 'undefined'
? false
: metadata.federation.mrf_policies.includes('TagPolicy'),
)
useInstanceStore().set({
name: 'federationPolicy',
path: 'federationPolicy',
value: federation,
})
useInstanceStore().set({
name: 'federating',
path: 'federating',
value:
typeof federation.enabled === 'undefined' ? true : federation.enabled,
})
const accountActivationRequired = metadata.accountActivationRequired
useInstanceStore().set({
name: 'accountActivationRequired',
path: 'accountActivationRequired',
value: accountActivationRequired,
})

View file

@ -33,6 +33,7 @@ import BookmarkFolders from '../components/bookmark_folders/bookmark_folders.vue
import QuotesTimeline from '../components/quotes_timeline/quotes_timeline.vue'
import { useInstanceStore } from 'src/stores/instance.js'
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
export default (store) => {
const validateAuthenticatedRoute = (to, from, next) => {
@ -205,7 +206,7 @@ export default (store) => {
},
]
if (useInstanceStore().featureSet.pleromaChatMessagesAvailable) {
if (useInstanceCapabilitiesStore().pleromaChatMessagesAvailable) {
routes = routes.concat([
{
name: 'chat',

View file

@ -6,7 +6,7 @@ import ConfirmModal from '../confirm_modal/confirm_modal.vue'
import Popover from '../popover/popover.vue'
import ProgressButton from '../progress_button/progress_button.vue'
import { useInstanceStore } from 'src/stores/instance.js'
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
import { useReportsStore } from 'src/stores/reports'
import { library } from '@fortawesome/fontawesome-svg-core'
@ -94,11 +94,10 @@ const AccountActions = {
shouldConfirmRemoveUserFromFollowers() {
return this.$store.getters.mergedConfig.modalOnRemoveUserFromFollowers
},
...mapState(useInstanceStore, {
blockExpirationSupported: (store) => store.featureSet.blockExpiration,
pleromaChatMessagesAvailable: (store) =>
store.featureSet.pleromaChatMessagesAvailable,
}),
...mapState(useInstanceCapabilitiesStore, [
'blockExpiration',
'pleromaChatMessagesAvailable',
]),
},
}

View file

@ -95,7 +95,7 @@
</Popover>
<teleport to="#modal">
<confirm-modal
v-if="showingConfirmBlock && !blockExpirationSupported"
v-if="showingConfirmBlock && !blockExpiration"
ref="blockDialog"
:title="$t('user_card.block_confirm_title')"
:confirm-text="$t('user_card.block_confirm_accept_button')"
@ -138,7 +138,7 @@
</i18n-t>
</confirm-modal>
<UserTimedFilterModal
v-if="blockExpirationSupported"
v-if="blockExpiration"
ref="timedBlockDialog"
:is-mute="false"
:user="user"

View file

@ -7,6 +7,7 @@ import StillImage from '../still-image/still-image.vue'
import VideoAttachment from '../video_attachment/video_attachment.vue'
import { useInstanceStore } from 'src/stores/instance.js'
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
import { useMediaViewerStore } from 'src/stores/media_viewer'
import { library } from '@fortawesome/fontawesome-svg-core'
@ -107,7 +108,7 @@ const Attachment = {
return 'file'
},
referrerpolicy() {
return useInstanceStore().featureSet.mediaProxyAvailable
return useInstanceCapabilitiesStore().mediaProxyAvailable
? ''
: 'no-referrer'
},

View file

@ -1,8 +1,9 @@
import { mapState } from 'pinia'
import UserTimedFilterModal from 'src/components/user_timed_filter_modal/user_timed_filter_modal.vue'
import BasicUserCard from '../basic_user_card/basic_user_card.vue'
import { useInstanceStore } from 'src/stores/instance.js'
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
const BlockCard = {
props: ['userId'],
@ -26,19 +27,18 @@ const BlockCard = {
new Date(this.user.mute_expires_at).toLocaleString(),
])
},
...mapState(useInstanceStore, {
blockExpirationSupported: (store) => store.featureSet.blockExpiration,
}),
...mapState(useInstanceCapabilitiesStore, ['blockExpiration']),
},
components: {
BasicUserCard,
UserTimedFilterModal,
},
methods: {
unblockUser() {
this.$store.dispatch('unblockUser', this.user.id)
},
blockUser() {
if (this.blockExpirationSupported) {
if (this.blockExpiration) {
this.$refs.timedBlockDialog.optionallyPrompt()
} else {
this.$store.dispatch('blockUser', { id: this.user.id })

View file

@ -16,7 +16,7 @@ export const ListsMenuContent = {
...mapPiniaState(useListsStore, {
lists: getListEntries,
}),
...mapPiniaState(useInstanceStore, ['private','federating']),
...mapPiniaState(useInstanceStore, ['private', 'federating']),
...mapState({
currentUser: (state) => state.users.currentUser,
}),

View file

@ -2,6 +2,7 @@ import DialogModal from '../dialog_modal/dialog_modal.vue'
import Popover from '../popover/popover.vue'
import { useInstanceStore } from 'src/stores/instance.js'
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
import { library } from '@fortawesome/fontawesome-svg-core'
import { faChevronDown } from '@fortawesome/free-solid-svg-icons'
@ -56,7 +57,7 @@ const ModerationTools = {
},
canUseTagPolicy() {
return (
useInstanceStore().featureSet.tagPolicyAvailable &&
useInstanceCapabilitiesStore().tagPolicyAvailable &&
this.privileged('users_manage_tags')
)
},

View file

@ -11,6 +11,7 @@ import NavigationPins from 'src/components/navigation/navigation_pins.vue'
import { useAnnouncementsStore } from 'src/stores/announcements'
import { useInstanceStore } from 'src/stores/instance.js'
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
import { useServerSideStorageStore } from 'src/stores/serverSideStorage'
import { library } from '@fortawesome/fontawesome-svg-core'
@ -112,14 +113,14 @@ const NavPanel = {
unreadAnnouncementCount: 'unreadAnnouncementCount',
supportsAnnouncements: (store) => store.supportsAnnouncements,
}),
...mapPiniaState(useInstanceCapabilitiesStore, [
'pleromaChatMessagesAvailable',
'pleromaBookmarkFoldersAvailable',
'localBubble',
]),
...mapPiniaState(useInstanceStore, ['federating']),
...mapPiniaState(useInstanceStore, {
privateMode: (store) => store.private,
pleromaChatMessagesAvailable: (store) =>
store.featureSet.pleromaChatMessagesAvailable,
bookmarkFolders: (store) =>
store.featureSet.pleromaBookmarkFoldersAvailable,
bubbleTimeline: (store) => store.featureSet.localBubble,
}),
...mapPiniaState(useServerSideStorageStore, {
collapsed: (store) => store.prefsStorage.simple.collapseNav,
@ -142,8 +143,8 @@ const NavPanel = {
isFederating: this.federating,
isPrivate: this.privateMode,
currentUser: this.currentUser,
supportsBubbleTimeline: this.bubbleTimeline,
supportsBookmarkFolders: this.bookmarkFolders,
supportsBubbleTimeline: this.localBubble,
supportsBookmarkFolders: this.pleromaBookmarkFoldersAvailable,
},
)
},
@ -156,8 +157,8 @@ const NavPanel = {
isFederating: this.federating,
isPrivate: this.privateMode,
currentUser: this.currentUser,
supportsBubbleTimeline: this.bubbleTimeline,
supportsBookmarkFolders: this.bookmarkFolders,
supportsBubbleTimeline: this.localBubble,
supportsBookmarkFolders: this.pleromaBookmarkFoldersAvailable,
},
)
},

View file

@ -84,7 +84,7 @@
/>
</div>
<NavigationEntry
v-if="currentUser && bookmarkFolders"
v-if="currentUser && pleromaBookmarkFoldersAvailable"
:show-pin="false"
:item="{ icon: 'bookmark', label: 'nav.bookmarks' }"
:aria-expanded="showBookmarkFolders ? 'true' : 'false'"

View file

@ -16,6 +16,7 @@ import StillImage from 'src/components/still-image/still-image.vue'
import { useAnnouncementsStore } from 'src/stores/announcements'
import { useBookmarkFoldersStore } from 'src/stores/bookmark_folders'
import { useInstanceStore } from 'src/stores/instance.js'
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
import { useListsStore } from 'src/stores/lists'
import { useServerSideStorageStore } from 'src/stores/serverSideStorage'
@ -73,12 +74,11 @@ const NavPanel = {
pinnedItems: (store) =>
new Set(store.prefsStorage.collections.pinnedNavItems),
}),
...mapPiniaState(useInstanceStore, {
pleromaChatMessagesAvailable: (store) =>
store.featureSet.pleromaChatMessagesAvailable,
bubbleTimeline: (store) => store.featureSet.localBubble,
}),
...mapPiniaState(useInstanceStore, ['private', 'federating']),
...mapPiniaState(useInstanceCapabilitiesStore, [
'pleromaChatMessagesAvailable',
'localBubble',
]),
...mapState({
currentUser: (state) => state.users.currentUser,
followRequestCount: (state) => state.api.followRequests.length,
@ -97,13 +97,11 @@ const NavPanel = {
isFederating: this.federating,
isPrivate: this.private,
currentUser: this.currentUser,
supportsBubbleTimeline: this.bubbleTimeline,
supportsBubbleTimeline: this.localBubble,
supportsBookmarkFolders: this.bookmarks,
},
)
}
console.log([...this.pinnedItems])
console.log([...this.bookmarks])
return filterNavigation(
[
...Object.entries({ ...TIMELINES })
@ -118,7 +116,7 @@ const NavPanel = {
{
hasChats: this.pleromaChatMessagesAvailable,
hasAnnouncements: this.supportsAnnouncements,
supportsBubbleTimeline: this.bubbleTimeline,
supportsBubbleTimeline: this.localBubble,
supportsBookmarkFolders: this.bookmarks,
isFederating: this.federating,
isPrivate: this.private,

View file

@ -22,6 +22,7 @@ import StatusContent from '../status_content/status_content.vue'
import { useEmojiStore } from 'src/stores/emoji.js'
import { useInstanceStore } from 'src/stores/instance.js'
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
import { useInterfaceStore } from 'src/stores/interface.js'
import { useMediaViewerStore } from 'src/stores/media_viewer.js'
@ -309,14 +310,14 @@ const PostStatusForm = {
return this.mergedConfig.alwaysShowSubjectInput
},
postFormats() {
return useInstanceStore().featureSet.postFormats || []
return useInstanceCapabilitiesStore().postFormats || []
},
safeDMEnabled() {
return useInstanceStore().featureSet.safeDM
return useInstanceCapabilitiesStore().safeDM
},
pollsAvailable() {
return (
useInstanceStore().featureSet.pollsAvailable &&
useInstanceCapabilitiesStore().pollsAvailable &&
useInstanceStore().limits.pollLimits.max_options >= 2 &&
this.disablePolls !== true
)
@ -346,7 +347,7 @@ const PostStatusForm = {
return typeof this.statusId !== 'undefined' && this.statusId.trim() !== ''
},
quotable() {
if (!useInstanceStore().featureSet.quotingAvailable) {
if (!useInstanceCapabilitiesStore().quotingAvailable) {
return false
}

View file

@ -15,6 +15,10 @@ export default {
type: String,
default: null,
},
description: {
type: String,
default: null,
},
path: {
type: [String, Array],
required: false,

View file

@ -35,11 +35,6 @@ export default {
type: Boolean,
default: false,
},
parentCollapsed: {
required: false,
type: Boolean,
default: null,
},
},
data() {
return {
@ -202,7 +197,6 @@ export default {
</div>
<div
role="tabpanel"
class={'contents' + (this.scrollableTabs ? ' scrollable-tabs' : '')}
v-body-scroll-lock={this.bodyScrollLock}
ref="contents"
>

View file

@ -3,7 +3,6 @@
ref="tabSwitcher"
class="settings_tab-switcher"
:scrollable-tabs="true"
:child-collapsed="childCollapsed"
:body-scroll-lock="bodyLock"
:hide-header="navHideHeader"
>

View file

@ -10,7 +10,7 @@ import IntegerSetting from '../helpers/integer_setting.vue'
import SharedComputedObject from '../helpers/shared_computed_object.js'
import UnitSetting from '../helpers/unit_setting.vue'
import { useInstanceStore } from 'src/stores/instance.js'
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
import { useServerSideStorageStore } from 'src/stores/serverSideStorage'
const ClutterTab = {
@ -25,14 +25,12 @@ const ClutterTab = {
},
computed: {
...SharedComputedObject(),
...mapState(useInstanceCapabilitiesStore, ['shoutAvailable']),
...mapState(useServerSideStorageStore, {
muteFilters: (store) =>
Object.entries(store.prefsStorage.simple.muteFilters),
muteFiltersObject: (store) => store.prefsStorage.simple.muteFilters,
}),
...mapState(useInstanceStore, {
blockExpirationSupported: (store) => store.featureSet.blockExpiration,
}),
onMuteDefaultActionLv1: {
get() {
const value = this.$store.state.config.onMuteDefaultAction

View file

@ -73,7 +73,7 @@
{{ $t('settings.user_card_hide_personal_marks') }}
</BooleanSetting>
</li>
<li v-if="instanceShoutboxPresent">
<li v-if="shoutAvailable">
<BooleanSetting
path="hideShoutbox"
>

View file

@ -1,4 +1,4 @@
import { mapState } from 'vuex'
import { mapState } from 'pinia'
import FontControl from 'src/components/font_control/font_control.vue'
import InterfaceLanguageSwitcher from 'src/components/interface_language_switcher/interface_language_switcher.vue'
@ -29,12 +29,6 @@ import {
library.add(faGlobe, faMessage, faPenAlt, faDatabase, faSliders)
const ComposingTab = {
props: {
parentCollapsed: {
required: true,
type: Boolean,
},
},
data() {
return {
subjectLineOptions: ['email', 'noop', 'masto'].map((mode) => ({
@ -132,9 +126,7 @@ const ComposingTab = {
},
},
...SharedComputedObject(),
...mapState(useInstanceStore, {
blockExpirationSupported: (store) => store.featureSet.blockExpiration,
}),
...mapState(useInstanceStore, ['blockExpiration']),
},
methods: {
changeDefaultScope(value) {

View file

@ -11,7 +11,7 @@ import IntegerSetting from '../helpers/integer_setting.vue'
import SharedComputedObject from '../helpers/shared_computed_object.js'
import UnitSetting from '../helpers/unit_setting.vue'
import { useInstanceStore } from 'src/stores/instance.js'
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
import { useInterfaceStore } from 'src/stores/interface'
import { useServerSideStorageStore } from 'src/stores/serverSideStorage'
@ -97,9 +97,7 @@ const FilteringTab = {
Object.entries(store.prefsStorage.simple.muteFilters),
muteFiltersObject: (store) => store.prefsStorage.simple.muteFilters,
}),
...mapState(useInstanceStore, {
blockExpirationSupported: (store) => store.featureSet.blockExpiration,
}),
...mapState(useInstanceCapabilitiesStore, ['blockExpiration']),
onMuteDefaultActionLv1: {
get() {
const value = this.$store.state.config.onMuteDefaultAction

View file

@ -47,7 +47,7 @@
</li>
</ul>
</li>
<li v-if="blockExpirationSupported">
<li v-if="blockExpiration">
<span class="setting-item">
<span class="setting-label">
{{ $t('user_card.default_block_expiration') }}

View file

@ -10,16 +10,11 @@ import SharedComputedObject from '../helpers/shared_computed_object.js'
import UnitSetting from '../helpers/unit_setting.vue'
import { useInstanceStore } from 'src/stores/instance.js'
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
import localeService from 'src/services/locale/locale.service.js'
const GeneralTab = {
props: {
parentCollapsed: {
required: true,
type: Boolean,
},
},
data() {
return {
absoluteTime12hOptions: ['24h', '12h'].map((mode) => ({
@ -52,9 +47,7 @@ const GeneralTab = {
},
},
...SharedComputedObject(),
...mapState(useInstanceStore, {
blockExpirationSupported: (store) => store.featureSet.blockExpiration,
}),
...mapState(useInstanceCapabilitiesStore, ['blockExpiration']),
},
methods: {
updateProfile() {

View file

@ -157,7 +157,7 @@
</BooleanSetting>
</li>
<li
v-if="!blockExpirationSupported"
v-if="!blockExpiration"
>
<BooleanSetting
path="modalOnBlock"

View file

@ -6,15 +6,9 @@ import ProfileSettingIndicator from '../helpers/profile_setting_indicator.vue'
import SharedComputedObject from '../helpers/shared_computed_object.js'
import UnitSetting from '../helpers/unit_setting.vue'
import { useInstanceStore } from 'src/stores/instance.js'
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
const GeneralTab = {
props: {
parentCollapsed: {
required: true,
type: Boolean,
},
},
data() {
return {
thirdColumnModeOptions: ['none', 'notifications', 'postform'].map(
@ -33,12 +27,11 @@ const GeneralTab = {
ProfileSettingIndicator,
},
computed: {
...mapState(useInstanceStore, {
postFormats: (store) => store.featureSet.postFormats || [],
instanceSpecificPanelPresent: (store) =>
store.instanceIdentity.instanceSpecificPanelPresent,
instanceShoutboxPresent: (store) => store.featureSet.shoutAvailable,
}),
...mapState(useInstanceCapabilitiesStore, [
'instanceSpecificPanelPresent',
'postFormats',
'suggestionsEnabled',
]),
columns() {
const mode = this.$store.getters.mergedConfig.thirdColumnMode

View file

@ -6,12 +6,6 @@ import ProfileSettingIndicator from '../helpers/profile_setting_indicator.vue'
import SharedComputedObject from '../helpers/shared_computed_object.js'
const GeneralTab = {
props: {
parentCollapsed: {
required: true,
type: Boolean,
},
},
data() {
return {
conversationDisplayOptions: ['tree', 'linear'].map((mode) => ({

View file

@ -3,6 +3,7 @@ import ProgressButton from 'src/components/progress_button/progress_button.vue'
import Mfa from './mfa.vue'
import { useInstanceStore } from 'src/stores/instance.js'
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
import { useOAuthTokensStore } from 'src/stores/oauth_tokens'
import localeService from 'src/services/locale/locale.service.js'
@ -45,7 +46,7 @@ const SecurityTab = {
return this.$store.state.users.currentUser
},
pleromaExtensionsAvailable() {
return useInstanceStore().featureSet.pleromaExtensionsAvailable
return useInstanceCapabilitiesStore().pleromaExtensionsAvailable
},
oauthTokens() {
return useOAuthTokensStore().tokens.map((oauthToken) => {

View file

@ -8,6 +8,7 @@ import UserCard from '../user_card/user_card.vue'
import { useAnnouncementsStore } from 'src/stores/announcements'
import { useInstanceStore } from 'src/stores/instance.js'
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
import { useInterfaceStore } from 'src/stores/interface'
import { useShoutStore } from 'src/stores/shout'
@ -95,14 +96,15 @@ const SideDrawer = {
'supportsAnnouncements',
'unreadAnnouncementCount',
]),
...mapState(useInstanceCapabilitiesStore, [
'pleromaChatMessagesAvailable',
'suggestionsEnabled',
]),
...mapState(useInstanceStore, ['private', 'federating']),
...mapState(useInstanceStore, {
logo: (store) => store.instanceIdentity.logo,
sitename: (store) => store.instanceIdentity.name,
hideSitename: (store) => store.instanceIdentity.hideSitename,
pleromaChatMessagesAvailable: (store) =>
store.featureSet.pleromaChatMessagesAvailable,
suggestionsEnabled: (store) => store.featureSet.suggestionsEnabled,
}),
...mapGetters(['unreadChatCount', 'draftCount']),
},

View file

@ -21,6 +21,7 @@ import UserListPopover from '../user_list_popover/user_list_popover.vue'
import UserPopover from '../user_popover/user_popover.vue'
import { useInstanceStore } from 'src/stores/instance.js'
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
import { useServerSideStorageStore } from 'src/stores/serverSideStorage'
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
@ -497,7 +498,7 @@ const Status = {
return this.status.edited_at !== null
},
editingAvailable() {
return useInstanceStore().featureSet.editingAvailable
return useInstanceCapabilitiesStore().editingAvailable
},
hasVisibleQuote() {
return this.status.quote_url && this.status.quote_visible

View file

@ -1,5 +1,6 @@
import { useEditStatusStore } from 'src/stores/editStatus.js'
import { useInstanceStore } from 'src/stores/instance.js'
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
import { useReportsStore } from 'src/stores/reports.js'
import { useStatusHistoryStore } from 'src/stores/statusHistory.js'
@ -161,7 +162,7 @@ export const BUTTONS = [
label: 'status.status_history',
if({ status, state }) {
return (
useInstanceStore().featureSet.editingAvailable &&
useInstanceCapabilitiesStore().editingAvailable &&
status.edited_at !== null
)
},
@ -193,7 +194,7 @@ export const BUTTONS = [
if({ status, loggedIn, currentUser, state }) {
return (
loggedIn &&
useInstanceStore().featureSet.editingAvailable &&
useInstanceCapabilitiesStore().editingAvailable &&
status.user.id === currentUser.id
)
},

View file

@ -10,6 +10,7 @@ import Popover from '../popover/popover.vue'
import { useBookmarkFoldersStore } from 'src/stores/bookmark_folders'
import { useInstanceStore } from 'src/stores/instance.js'
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
import { useInterfaceStore } from 'src/stores/interface'
import { useListsStore } from 'src/stores/lists'
@ -61,14 +62,13 @@ const TimelineMenu = {
(route === 'bookmark-folder' || route === 'bookmarks')
)
},
...mapPiniaState(useInstanceCapabilitiesStore, [
'pleromaChatMessagesAvailable',
'pleromaBookmarkFoldersAvailable',
'bookmarkFolders',
'localBubble',
]),
...mapPiniaState(useInstanceStore, ['private', 'federating']),
...mapPiniaState(useInstanceStore, {
pleromaChatMessagesAvailable: (store) =>
store.featureSet.pleromaChatMessagesAvailable,
bookmarkFolders: (store) =>
store.featureSet.pleromaBookmarkFoldersAvailable,
bubbleTimeline: (store) => store.featureSet.localBubble,
}),
...mapState({
currentUser: (state) => state.users.currentUser,
}),
@ -80,8 +80,8 @@ const TimelineMenu = {
isFederating: this.federating,
isPrivate: this.private,
currentUser: this.currentUser,
supportsBookmarkFolders: this.bookmarkFolders,
supportsBubbleTimeline: this.bubbleTimeline,
supportsBookmarkFolders: this.pleromaBookmarkFoldersAvailable,
supportsBubbleTimeline: this.localBubble,
},
)
},

View file

@ -25,6 +25,7 @@ import UserNote from '../user_note/user_note.vue'
import { useEmojiStore } from 'src/stores/emoji.js'
import { useInstanceStore } from 'src/stores/instance.js'
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
import { usePostStatusStore } from 'src/stores/post_status'
import { propsToNative } from 'src/services/attributes_helper/attributes_helper.service.js'
@ -180,7 +181,7 @@ export default {
return false
},
groupActorAvailable() {
return useInstanceStore().featureSet.groupActorAvailable
return useInstanceCapabilitiesStore().groupActorAvailable
},
availableActorTypes() {
return this.groupActorAvailable

View file

@ -10,6 +10,7 @@ import Timeline from '../timeline/timeline.vue'
import UserCard from '../user_card/user_card.vue'
import { useInstanceStore } from 'src/stores/instance.js'
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
import { library } from '@fortawesome/fontawesome-svg-core'
import { faCircleNotch } from '@fortawesome/free-solid-svg-icons'
@ -89,7 +90,7 @@ const UserProfile = {
favoritesTabVisible() {
return (
this.isUs ||
(useInstanceStore().featureSet.pleromaPublicFavouritesAvailable &&
(useInstanceCapabilitiesStore().pleromaPublicFavouritesAvailable &&
!this.user.hide_favorites)
)
},

View file

@ -3,6 +3,7 @@ import { shuffle } from 'lodash'
import apiService from '../../services/api/api.service.js'
import { useInstanceStore } from 'src/stores/instance.js'
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
@ -49,7 +50,7 @@ const WhoToFollowPanel = {
return this.$store.state.users.currentUser.screen_name
},
suggestionsEnabled() {
return useInstanceStore().featureSet.suggestionsEnabled
return useInstanceCapabilitiesStore().suggestionsEnabled
},
},
methods: {

View file

@ -5,6 +5,7 @@ import backendInteractorService from '../services/backend_interactor_service/bac
import { maybeShowChatNotification } from '../services/chat_utils/chat_utils.js'
import { useInstanceStore } from 'src/stores/instance.js'
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
import { useInterfaceStore } from 'src/stores/interface.js'
import { useShoutStore } from 'src/stores/shout.js'
@ -239,7 +240,7 @@ const api = {
) {
if (
timeline === 'favourites' &&
!useInstanceStore().featureSet.pleromaPublicFavouritesAvailable
!useInstanceCapabilitiesStore().pleromaPublicFavouritesAvailable
)
return
if (store.state.fetchers[timeline]) return
@ -324,7 +325,8 @@ const api = {
// Bookmark folders
startFetchingBookmarkFolders(store) {
if (store.state.fetchers.bookmarkFolders) return
if (!useInstanceStore().featureSet.pleromaBookmarkFoldersAvailable) return
if (!useInstanceCapabilitiesStore().pleromaBookmarkFoldersAvailable)
return
const fetcher =
store.state.backendInteractor.startFetchingBookmarkFolders({ store })
store.commit('addFetcher', { fetcherName: 'bookmarkFolders', fetcher })

View file

@ -59,7 +59,6 @@ const config = {
},
mergedConfig(state) {
const instancePrefs = useInstanceStore().prefsStorage
console.log(state)
const result = Object.fromEntries(
Object.keys(defaultState).map((key) => [
key,

View file

@ -23,6 +23,7 @@ import {
import { useEmojiStore } from 'src/stores/emoji.js'
import { useInstanceStore } from 'src/stores/instance.js'
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
import { useInterfaceStore } from 'src/stores/interface.js'
import { useOAuthStore } from 'src/stores/oauth.js'
import { useServerSideStorageStore } from 'src/stores/serverSideStorage'
@ -766,7 +767,7 @@ const users = {
dispatch('startFetchingNotifications')
if (
useInstanceStore().featureSet.pleromaChatMessagesAvailable
useInstanceCapabilitiesStore().pleromaChatMessagesAvailable
) {
// Start fetching chats
dispatch('startFetchingChats')

View file

@ -2,6 +2,7 @@ import apiService from '../api/api.service.js'
import { promiseInterval } from '../promise_interval/promise_interval.js'
import { useInstanceStore } from 'src/stores/instance.js'
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
import { useInterfaceStore } from 'src/stores/interface.js'
const update = ({ store, notifications, older }) => {
@ -30,7 +31,7 @@ const fetchAndUpdate = ({ store, credentials, older = false, since }) => {
const timelineData = rootState.notifications
const hideMutedPosts = getters.mergedConfig.hideMutedPosts
if (useInstanceStore().featureSet.pleromaChatMessagesAvailable) {
if (useInstanceCapabilitiesStore().pleromaChatMessagesAvailable) {
mastoApiNotificationTypes.add('pleroma:chat_mention')
}

View file

@ -4,6 +4,7 @@ import apiService from '../api/api.service.js'
import { promiseInterval } from '../promise_interval/promise_interval.js'
import { useInstanceStore } from 'src/stores/instance.js'
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
import { useInterfaceStore } from 'src/stores/interface.js'
const update = ({
@ -78,7 +79,7 @@ const fetchAndUpdate = ({
.then((response) => {
if (response.errors) {
if (timeline === 'favorites') {
useInstanceStore().featureSet.pleromaPublicFavouritesAvailable = false
useInstanceCapabilitiesStore().pleromaPublicFavouritesAvailable = false
return
}
throw new Error(`${response.status} ${response.statusText}`)

View file

@ -69,31 +69,6 @@ const defaultState = {
restrictedNicknames: [],
localBubbleInstances: [], // Akkoma
// Feature-set, apparently, not everything here is reported...
featureSet: {
postFormats: [],
mailerEnabled: false,
safeDM: true,
shoutAvailable: false,
pleromaExtensionsAvailable: true,
pleromaChatMessagesAvailable: false,
pleromaCustomEmojiReactionsAvailable: false,
pleromaBookmarkFoldersAvailable: false,
pleromaPublicFavouritesAvailable: true,
statusNotificationTypeAvailable: true,
gopherAvailable: false,
editingAvailable: false,
mediaProxyAvailable: false,
suggestionsEnabled: false,
suggestionsWeb: '',
quotingAvailable: false,
groupActorAvailable: false,
blockExpiration: false,
tagPolicyAvailable: false,
pollsAvailable: false,
localBubble: false, // Akkoma
},
// Version Information
backendVersion: '',
backendRepository: '',
@ -118,17 +93,10 @@ export const useInstanceStore = defineStore('instance', {
console.error(
`Unknown instance option ${path ?? name}, value: ${value}`,
)
set(this, path ?? name, value)
switch (name) {
case 'name':
useInterfaceStore().setPageTitle()
break
case 'shoutAvailable':
if (value) {
window.vuex.dispatch('initializeSocket')
}
break
}
if ((path ?? name) === 'name') useInterfaceStore().setPageTitle()
},
async getKnownDomains() {
try {

View file

@ -0,0 +1,47 @@
import { defineStore } from 'pinia'
const defaultState = {
postFormats: [],
mailerEnabled: false,
safeDM: true,
shoutAvailable: false,
pleromaExtensionsAvailable: true,
pleromaChatMessagesAvailable: false,
pleromaCustomEmojiReactionsAvailable: false,
pleromaBookmarkFoldersAvailable: false,
pleromaPublicFavouritesAvailable: true,
statusNotificationTypeAvailable: true,
gopherAvailable: false,
editingAvailable: false,
mediaProxyAvailable: false,
suggestionsEnabled: false,
suggestionsWeb: '',
quotingAvailable: false,
groupActorAvailable: false,
blockExpiration: false,
tagPolicyAvailable: false,
pollsAvailable: false,
localBubble: false, // Akkoma
}
export const useInstanceCapabilitiesStore = defineStore(
'instance-capabilities',
{
state: () => ({ ...defaultState }),
actions: {
set(capability, value) {
if (!Object.hasOwn(defaultState, capability)) {
console.error(
`Unknown instance capability ${capability}, value: ${value}`,
)
}
this[capability] = value
if (capability === 'shoutAvailable') {
window.vuex.dispatch('initializeSocket')
}
},
},
},
)