diff --git a/CHANGELOG.md b/CHANGELOG.md index b3d38ea24..1eb5a9cb4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,15 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). +## 2.10.1 +### Fixed +- fixed being unable to set actor type from profile page +- fixed error when clicking mute menu itself (instead of submenu items) +- fixed mute -> domain status submenu not working + +### Internal +- Add playwright E2E-tests with an optional docker-based backend + ## 2.10.0 ### Changed - Temporary changes modal now shows actual countdown instead of fixed timeout diff --git a/biome.json b/biome.json index d64639d52..6a464a0e5 100644 --- a/biome.json +++ b/biome.json @@ -132,7 +132,11 @@ "groups": [ [":NODE:", ":PACKAGE:", "!src/**", "!@fortawesome/**"], ":BLANK_LINE:", - [":PATH:", "src/**"], + [":PATH:", "src/components/**"], + ":BLANK_LINE:", + [":PATH:", "src/stores/**"], + ":BLANK_LINE:", + [":PATH:", "src/**", "src/stores/**", "src/components/**"], ":BLANK_LINE:", "@fortawesome/fontawesome-svg-core", "@fortawesome/*" diff --git a/changelog.d/actor-type.fix b/changelog.d/actor-type.fix deleted file mode 100644 index a2c873c1a..000000000 --- a/changelog.d/actor-type.fix +++ /dev/null @@ -1 +0,0 @@ -fixed being unable to set actor type from profile page diff --git a/changelog.d/biome.skip b/changelog.d/biome.skip deleted file mode 100644 index e69de29bb..000000000 diff --git a/changelog.d/e2e-tests.add b/changelog.d/e2e-tests.add deleted file mode 100644 index ba62b25ac..000000000 --- a/changelog.d/e2e-tests.add +++ /dev/null @@ -1 +0,0 @@ -Add playwright E2E-tests with an optional docker-based backend diff --git a/changelog.d/e2e.skip b/changelog.d/e2e.skip deleted file mode 100644 index e84c25121..000000000 --- a/changelog.d/e2e.skip +++ /dev/null @@ -1 +0,0 @@ -fix e2e diff --git a/package.json b/package.json index b00ed545a..bdd1acfbe 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pleroma_fe", - "version": "2.10.0", + "version": "2.10.1", "description": "Pleroma frontend, the default frontend of Pleroma social network server", "author": "Pleroma contributors ", "private": false, diff --git a/src/App.js b/src/App.js index 33645c63d..916b5b33a 100644 --- a/src/App.js +++ b/src/App.js @@ -1,4 +1,5 @@ import { throttle } from 'lodash' +import { mapState } from 'pinia' import { defineAsyncComponent } from 'vue' import { mapGetters } from 'vuex' @@ -20,8 +21,10 @@ 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 { useInterfaceStore } from './stores/interface' -import { useShoutStore } from './stores/shout' + +import { useInstanceStore } from 'src/stores/instance.js' +import { useInterfaceStore } from 'src/stores/interface.js' +import { useShoutStore } from 'src/stores/shout.js' export default { name: 'app', @@ -91,12 +94,9 @@ export default { this.scrollParent.removeEventListener('scroll', this.updateScrollState) }, computed: { - themeApplied() { - return useInterfaceStore().themeApplied - }, currentTheme() { - if (useInterfaceStore().styleDataUsed) { - const styleMeta = useInterfaceStore().styleDataUsed.find( + if (this.styleDataUsed) { + const styleMeta = this.styleDataUsed.find( (x) => x.component === '@meta', ) @@ -134,9 +134,7 @@ export default { return this.currentUser.background_image }, instanceBackground() { - return this.mergedConfig.hideInstanceWallpaper - ? null - : this.$store.state.instance.background + return this.mergedConfig.hideInstanceWallpaper ? null : this.background }, background() { return this.userBackground || this.instanceBackground @@ -151,14 +149,11 @@ export default { shout() { return useShoutStore().joined }, - suggestionsEnabled() { - return this.$store.state.instance.suggestionsEnabled - }, showInstanceSpecificPanel() { return ( - this.$store.state.instance.showInstanceSpecificPanel && + this.showInstanceSpecificPanel && !this.$store.getters.mergedConfig.hideISP && - this.$store.state.instance.instanceSpecificPanelContent + this.instanceSpecificPanelContent ) }, isChats() { @@ -175,24 +170,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 }, hideShoutbox() { return this.$store.getters.mergedConfig.hideShoutbox }, - layoutType() { - return useInterfaceStore().layoutType - }, - privateMode() { - return this.$store.state.instance.private - }, reverseLayout() { const { thirdColumnMode, sidebarRight: reverseSetting } = this.$store.getters.mergedConfig @@ -214,6 +197,22 @@ export default { return window /* this.$refs.appContentRef */ }, ...mapGetters(['mergedConfig']), + ...mapState(useInterfaceStore, [ + 'themeApplied', + 'styleDataUsed', + 'layoutType', + ]), + ...mapState(useInstanceStore, ['styleDataUsed', 'private']), + ...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, + }), }, methods: { resizeHandler() { diff --git a/src/boot/after_store.js b/src/boot/after_store.js index 1a2be5bd7..a970d25cc 100644 --- a/src/boot/after_store.js +++ b/src/boot/after_store.js @@ -14,16 +14,6 @@ import { config.autoAddCss = false -import VBodyScrollLock from 'src/directives/body_scroll_lock' -import { - instanceDefaultConfig, - staticOrApiConfigDefault, -} from 'src/modules/default_config_state.js' -import { useAnnouncementsStore } from 'src/stores/announcements' -import { useAuthFlowStore } from 'src/stores/auth_flow' -import { useI18nStore } from 'src/stores/i18n' -import { useInterfaceStore } from 'src/stores/interface' -import { useOAuthStore } from 'src/stores/oauth' import App from '../App.vue' import backendInteractorService from '../services/backend_interactor_service/backend_interactor_service.js' import FaviconService from '../services/favicon_service/favicon_service.js' @@ -35,6 +25,20 @@ import { } from '../services/window_utils/window_utils' import routes from './routes' +import { useAnnouncementsStore } from 'src/stores/announcements' +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 { useInterfaceStore } from 'src/stores/interface.js' +import { useOAuthStore } from 'src/stores/oauth' + +import VBodyScrollLock from 'src/directives/body_scroll_lock' +import { + instanceDefaultConfig, + staticOrApiConfigDefault, +} from 'src/modules/default_config_state.js' + let staticInitialResults = null const parsedInitialResults = () => { @@ -78,29 +82,29 @@ const getInstanceConfig = async ({ store }) => { const textlimit = data.max_toot_chars const vapidPublicKey = data.pleroma.vapid_public_key - store.dispatch('setInstanceOption', { - name: 'pleromaExtensionsAvailable', + useInstanceStore().set({ + name: 'featureSet.pleromaExtensionsAvailable', value: data.pleroma, }) - store.dispatch('setInstanceOption', { + useInstanceStore().set({ name: 'textlimit', value: textlimit, }) - store.dispatch('setInstanceOption', { + useInstanceStore().set({ name: 'accountApprovalRequired', value: data.approval_required, }) - store.dispatch('setInstanceOption', { + useInstanceStore().set({ name: 'birthdayRequired', value: !!data.pleroma?.metadata.birthday_required, }) - store.dispatch('setInstanceOption', { + useInstanceStore().set({ name: 'birthdayMinAge', value: data.pleroma?.metadata.birthday_min_age || 0, }) if (vapidPublicKey) { - store.dispatch('setInstanceOption', { + useInstanceStore().set({ name: 'vapidPublicKey', value: vapidPublicKey, }) @@ -161,14 +165,18 @@ const setSettings = async ({ apiConfig, staticConfig, store }) => { config = Object.assign({}, staticConfig, apiConfig) } - const copyInstanceOption = (name) => { - if (typeof config[name] !== 'undefined') { - store.dispatch('setInstanceOption', { name, value: config[name] }) + const copyInstanceOption = ({ source, destination }) => { + if (typeof config[source] !== 'undefined') { + useInstanceStore().set({ path: destination, value: config[source] }) } } - Object.keys(staticOrApiConfigDefault).forEach(copyInstanceOption) - Object.keys(instanceDefaultConfig).forEach(copyInstanceOption) + Object.keys(staticOrApiConfigDefault) + .map((k) => ({ source: k, destination: `instanceIdentity.${k}` })) + .forEach(copyInstanceOption) + Object.keys(instanceDefaultConfig) + .map((k) => ({ source: k, destination: `prefsStorage.${k}` })) + .forEach(copyInstanceOption) useAuthFlowStore().setInitialStrategy(config.loginMethod) } @@ -178,7 +186,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({ name: 'instanceIdentity.tos', value: html }) } else { throw res } @@ -192,8 +200,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({ + name: 'instanceIdentity.instanceSpecificPanelContent', value: html, }) } else { @@ -227,7 +235,7 @@ const getStickers = async ({ store }) => { ).sort((a, b) => { return a.meta.title.localeCompare(b.meta.title) }) - store.dispatch('setInstanceOption', { name: 'stickers', value: stickers }) + useEmojiStore().setStickers(stickers) } else { throw res } @@ -248,7 +256,7 @@ const getAppSecret = async ({ store }) => { const resolveStaffAccounts = ({ store, accounts }) => { const nicknames = accounts.map((uri) => uri.split('/').pop()) - store.dispatch('setInstanceOption', { + useInstanceStore().set({ name: 'staffAccounts', value: nicknames, }) @@ -262,159 +270,163 @@ 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', - 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: 'localBubbleInstances', value: metadata.localBubbleInstances ?? [], }) + useInstanceStore().set({ + path: 'featureSet.localBubble', + value: (metadata.localBubbleInstances ?? []).length > 0, + }) + useInstanceStore().set({ + path: 'limits.pollLimits', + value: metadata.pollLimits, + }) const uploadLimits = metadata.uploadLimits - store.dispatch('setInstanceOption', { - name: 'uploadlimit', + useInstanceStore().set({ + name: 'limits.uploadlimit', value: parseInt(uploadLimits.general), }) - store.dispatch('setInstanceOption', { - name: 'avatarlimit', + useInstanceStore().set({ + name: 'limits.avatarlimit', value: parseInt(uploadLimits.avatar), }) - store.dispatch('setInstanceOption', { - name: 'backgroundlimit', + useInstanceStore().set({ + name: 'limits.backgroundlimit', value: parseInt(uploadLimits.background), }) - store.dispatch('setInstanceOption', { - name: 'bannerlimit', + useInstanceStore().set({ + name: 'limits.bannerlimit', value: parseInt(uploadLimits.banner), }) - store.dispatch('setInstanceOption', { - name: 'fieldsLimits', + useInstanceStore().set({ + name: 'limits.fieldsLimits', value: metadata.fieldsLimits, }) - store.dispatch('setInstanceOption', { + useInstanceStore().set({ name: 'restrictedNicknames', value: metadata.restrictedNicknames, }) - store.dispatch('setInstanceOption', { - name: 'postFormats', + useInstanceStore().set({ + name: 'featureSet.postFormats', value: metadata.postFormats, }) const suggestions = metadata.suggestions - store.dispatch('setInstanceOption', { - name: 'suggestionsEnabled', + useInstanceStore().set({ + name: 'featureSet.suggestionsEnabled', value: suggestions.enabled, }) - store.dispatch('setInstanceOption', { - name: 'suggestionsWeb', + useInstanceStore().set({ + name: 'featureSet.suggestionsWeb', value: suggestions.web, }) const software = data.software - store.dispatch('setInstanceOption', { + useInstanceStore().set({ name: 'backendVersion', value: software.version, }) - store.dispatch('setInstanceOption', { + useInstanceStore().set({ name: 'backendRepository', value: software.repository, }) const priv = metadata.private - store.dispatch('setInstanceOption', { name: 'private', value: priv }) + useInstanceStore().set({ name: 'private', value: priv }) const frontendVersion = window.___pleromafe_commit_hash - store.dispatch('setInstanceOption', { + useInstanceStore().set({ name: 'frontendVersion', value: frontendVersion, }) const federation = metadata.federation - store.dispatch('setInstanceOption', { - name: 'tagPolicyAvailable', + useInstanceStore().set({ + name: 'featureSet.tagPolicyAvailable', value: typeof federation.mrf_policies === 'undefined' ? false : metadata.federation.mrf_policies.includes('TagPolicy'), }) - store.dispatch('setInstanceOption', { + useInstanceStore().set({ name: 'federationPolicy', value: federation, }) - store.dispatch('setInstanceOption', { + useInstanceStore().set({ name: 'federating', value: typeof federation.enabled === 'undefined' ? true : federation.enabled, }) const accountActivationRequired = metadata.accountActivationRequired - store.dispatch('setInstanceOption', { + useInstanceStore().set({ name: 'accountActivationRequired', value: accountActivationRequired, }) @@ -526,7 +538,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({ name: 'server', value: server }) await setConfig({ store }) try { diff --git a/src/boot/routes.js b/src/boot/routes.js index 3296755a1..c5876a3d4 100644 --- a/src/boot/routes.js +++ b/src/boot/routes.js @@ -32,12 +32,16 @@ import BookmarkFolderEdit from '../components/bookmark_folder_edit/bookmark_fold 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' + export default (store) => { const validateAuthenticatedRoute = (to, from, next) => { if (store.state.users.currentUser) { next() } else { - next(store.state.instance.redirectRootNoLogin || '/main/all') + next( + useInstanceStore().instanceIdentity.redirectRootNoLogin || '/main/all', + ) } } @@ -48,8 +52,9 @@ export default (store) => { redirect: () => { return ( (store.state.users.currentUser - ? store.state.instance.redirectRootLogin - : store.state.instance.redirectRootNoLogin) || '/main/all' + ? useInstanceStore().instanceIdentity.redirectRootLogin + : useInstanceStore().instanceIdentity.redirectRootNoLogin) || + '/main/all' ) }, }, @@ -200,7 +205,7 @@ export default (store) => { }, ] - if (store.state.instance.pleromaChatMessagesAvailable) { + if (useInstanceStore().featureSet.pleromaChatMessagesAvailable) { routes = routes.concat([ { name: 'chat', diff --git a/src/components/about/about.js b/src/components/about/about.js index d091dfd0a..f52d5c797 100644 --- a/src/components/about/about.js +++ b/src/components/about/about.js @@ -4,6 +4,8 @@ import MRFTransparencyPanel from '../mrf_transparency_panel/mrf_transparency_pan import StaffPanel from '../staff_panel/staff_panel.vue' import TermsOfServicePanel from '../terms_of_service_panel/terms_of_service_panel.vue' +import { useInstanceStore } from 'src/stores/instance.js' + const About = { components: { InstanceSpecificPanel, @@ -14,13 +16,13 @@ const About = { }, computed: { showFeaturesPanel() { - return this.$store.state.instance.showFeaturesPanel + return useInstanceStore().instanceIdentity.showFeaturesPanel }, showInstanceSpecificPanel() { return ( - this.$store.state.instance.showInstanceSpecificPanel && + useInstanceStore().instanceIdentity.showInstanceSpecificPanel && !this.$store.getters.mergedConfig.hideISP && - this.$store.state.instance.instanceSpecificPanelContent + useInstanceStore().instanceIdentity.instanceSpecificPanelContent ) }, }, diff --git a/src/components/account_actions/account_actions.js b/src/components/account_actions/account_actions.js index ee94dc544..1910d3544 100644 --- a/src/components/account_actions/account_actions.js +++ b/src/components/account_actions/account_actions.js @@ -1,12 +1,14 @@ -import { mapState } from 'vuex' +import { mapState } from 'pinia' import UserListMenu from 'src/components/user_list_menu/user_list_menu.vue' import UserTimedFilterModal from 'src/components/user_timed_filter_modal/user_timed_filter_modal.vue' -import { useReportsStore } from 'src/stores/reports' 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 { useReportsStore } from 'src/stores/reports' + import { library } from '@fortawesome/fontawesome-svg-core' import { faEllipsisV } from '@fortawesome/free-solid-svg-icons' @@ -92,10 +94,10 @@ const AccountActions = { shouldConfirmRemoveUserFromFollowers() { return this.$store.getters.mergedConfig.modalOnRemoveUserFromFollowers }, - ...mapState({ - blockExpirationSupported: (state) => state.instance.blockExpiration, - pleromaChatMessagesAvailable: (state) => - state.instance.pleromaChatMessagesAvailable, + ...mapState(useInstanceStore, { + blockExpirationSupported: (store) => store.featureSet.blockExpiration, + pleromaChatMessagesAvailable: (store) => + store.featureSet.pleromaChatMessagesAvailable, }), }, } diff --git a/src/components/announcement/announcement.js b/src/components/announcement/announcement.js index 906b84ce2..13d55c159 100644 --- a/src/components/announcement/announcement.js +++ b/src/components/announcement/announcement.js @@ -1,10 +1,11 @@ import { mapState } from 'vuex' -import { useAnnouncementsStore } from 'src/stores/announcements' import localeService from '../../services/locale/locale.service.js' import AnnouncementEditor from '../announcement_editor/announcement_editor.vue' import RichContent from '../rich_content/rich_content.jsx' +import { useAnnouncementsStore } from 'src/stores/announcements.js' + const Announcement = { components: { AnnouncementEditor, diff --git a/src/components/announcements_page/announcements_page.js b/src/components/announcements_page/announcements_page.js index 0c4383d2e..b8b1f000a 100644 --- a/src/components/announcements_page/announcements_page.js +++ b/src/components/announcements_page/announcements_page.js @@ -1,9 +1,10 @@ import { mapState } from 'vuex' -import { useAnnouncementsStore } from 'src/stores/announcements' import Announcement from '../announcement/announcement.vue' import AnnouncementEditor from '../announcement_editor/announcement_editor.vue' +import { useAnnouncementsStore } from 'src/stores/announcements.js' + const AnnouncementsPage = { components: { Announcement, diff --git a/src/components/attachment/attachment.js b/src/components/attachment/attachment.js index 31fceba60..d1884ba5c 100644 --- a/src/components/attachment/attachment.js +++ b/src/components/attachment/attachment.js @@ -1,12 +1,14 @@ import { mapGetters } from 'vuex' -import { useMediaViewerStore } from 'src/stores/media_viewer' import nsfwImage from '../../assets/nsfw.png' import fileTypeService from '../../services/file_type/file_type.service.js' import Flash from '../flash/flash.vue' import StillImage from '../still-image/still-image.vue' import VideoAttachment from '../video_attachment/video_attachment.vue' +import { useInstanceStore } from 'src/stores/instance.js' +import { useMediaViewerStore } from 'src/stores/media_viewer' + import { library } from '@fortawesome/fontawesome-svg-core' import { faAlignRight, @@ -53,7 +55,8 @@ const Attachment = { data() { return { localDescription: this.description || this.attachment.description, - nsfwImage: this.$store.state.instance.nsfwCensorImage || nsfwImage, + nsfwImage: + useInstanceStore().instanceIdentity.nsfwCensorImage || nsfwImage, hideNsfwLocal: this.$store.getters.mergedConfig.hideNsfw, preloadImage: this.$store.getters.mergedConfig.preloadImage, loading: false, @@ -104,7 +107,9 @@ const Attachment = { return 'file' }, referrerpolicy() { - return this.$store.state.instance.mediaProxyAvailable ? '' : 'no-referrer' + return useInstanceStore().featureSet.mediaProxyAvailable + ? '' + : 'no-referrer' }, type() { return fileTypeService.fileType(this.attachment.mimetype) diff --git a/src/components/auth_form/auth_form.js b/src/components/auth_form/auth_form.js index ce88aa6f9..9e05095ca 100644 --- a/src/components/auth_form/auth_form.js +++ b/src/components/auth_form/auth_form.js @@ -1,11 +1,12 @@ import { mapState } from 'pinia' import { h, resolveComponent } from 'vue' -import { useAuthFlowStore } from 'src/stores/auth_flow' import LoginForm from '../login_form/login_form.vue' import MFARecoveryForm from '../mfa_form/recovery_form.vue' import MFATOTPForm from '../mfa_form/totp_form.vue' +import { useAuthFlowStore } from 'src/stores/auth_flow.js' + const AuthForm = { name: 'AuthForm', render() { diff --git a/src/components/avatar_list/avatar_list.js b/src/components/avatar_list/avatar_list.js index aad157686..830b64219 100644 --- a/src/components/avatar_list/avatar_list.js +++ b/src/components/avatar_list/avatar_list.js @@ -1,6 +1,9 @@ -import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator' import UserAvatar from '../user_avatar/user_avatar.vue' +import { useInstanceStore } from 'src/stores/instance.js' + +import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator' + const AvatarList = { props: ['users'], computed: { @@ -16,7 +19,7 @@ const AvatarList = { return generateProfileLink( user.id, user.screen_name, - this.$store.state.instance.restrictedNicknames, + useInstanceStore().restrictedNicknames, ) }, }, diff --git a/src/components/basic_user_card/basic_user_card.js b/src/components/basic_user_card/basic_user_card.js index cc4cbce44..0e45b140a 100644 --- a/src/components/basic_user_card/basic_user_card.js +++ b/src/components/basic_user_card/basic_user_card.js @@ -1,9 +1,12 @@ import RichContent from 'src/components/rich_content/rich_content.jsx' -import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator' import UserAvatar from '../user_avatar/user_avatar.vue' import UserLink from '../user_link/user_link.vue' import UserPopover from '../user_popover/user_popover.vue' +import { useInstanceStore } from 'src/stores/instance.js' + +import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator' + const BasicUserCard = { props: ['user'], components: { @@ -17,7 +20,7 @@ const BasicUserCard = { return generateProfileLink( user.id, user.screen_name, - this.$store.state.instance.restrictedNicknames, + useInstanceStore().restrictedNicknames, ) }, }, diff --git a/src/components/block_card/block_card.js b/src/components/block_card/block_card.js index 7301bf0c7..8101394dd 100644 --- a/src/components/block_card/block_card.js +++ b/src/components/block_card/block_card.js @@ -1,7 +1,9 @@ -import { mapState } from 'vuex' +import { mapState } from 'pinia' import BasicUserCard from '../basic_user_card/basic_user_card.vue' +import { useInstanceStore } from 'src/stores/instance.js' + const BlockCard = { props: ['userId'], computed: { @@ -24,8 +26,8 @@ const BlockCard = { new Date(this.user.mute_expires_at).toLocaleString(), ]) }, - ...mapState({ - blockExpirationSupported: (state) => state.instance.blockExpiration, + ...mapState(useInstanceStore, { + blockExpirationSupported: (store) => store.featureSet.blockExpiration, }), }, components: { diff --git a/src/components/bookmark_folder_edit/bookmark_folder_edit.js b/src/components/bookmark_folder_edit/bookmark_folder_edit.js index a658a0f40..a036895bf 100644 --- a/src/components/bookmark_folder_edit/bookmark_folder_edit.js +++ b/src/components/bookmark_folder_edit/bookmark_folder_edit.js @@ -1,8 +1,9 @@ -import { useBookmarkFoldersStore } from 'src/stores/bookmark_folders' -import { useInterfaceStore } from 'src/stores/interface' import apiService from '../../services/api/api.service' import EmojiPicker from '../emoji_picker/emoji_picker.vue' +import { useBookmarkFoldersStore } from 'src/stores/bookmark_folders.js' +import { useInterfaceStore } from 'src/stores/interface.js' + const BookmarkFolderEdit = { data() { return { diff --git a/src/components/bookmark_folders/bookmark_folders.js b/src/components/bookmark_folders/bookmark_folders.js index 8e09abb31..1147fd3a5 100644 --- a/src/components/bookmark_folders/bookmark_folders.js +++ b/src/components/bookmark_folders/bookmark_folders.js @@ -1,6 +1,7 @@ -import { useBookmarkFoldersStore } from 'src/stores/bookmark_folders' import BookmarkFolderCard from '../bookmark_folder_card/bookmark_folder_card.vue' +import { useBookmarkFoldersStore } from 'src/stores/bookmark_folders.js' + const BookmarkFolders = { data() { return { diff --git a/src/components/bookmark_folders_menu/bookmark_folders_menu_content.js b/src/components/bookmark_folders_menu/bookmark_folders_menu_content.js index e84b3bc85..be1fb06ea 100644 --- a/src/components/bookmark_folders_menu/bookmark_folders_menu_content.js +++ b/src/components/bookmark_folders_menu/bookmark_folders_menu_content.js @@ -2,7 +2,8 @@ import { mapState } from 'pinia' import { getBookmarkFolderEntries } from 'src/components/navigation/filter.js' import NavigationEntry from 'src/components/navigation/navigation_entry.vue' -import { useBookmarkFoldersStore } from 'src/stores/bookmark_folders' + +import { useBookmarkFoldersStore } from 'src/stores/bookmark_folders.js' export const BookmarkFoldersMenuContent = { props: ['showPin'], diff --git a/src/components/chat/chat.js b/src/components/chat/chat.js index 6dd69ada4..caeb2aea7 100644 --- a/src/components/chat/chat.js +++ b/src/components/chat/chat.js @@ -2,7 +2,6 @@ import _ from 'lodash' import { mapState as mapPiniaState } from 'pinia' import { mapGetters, mapState } from 'vuex' -import { useInterfaceStore } from 'src/stores/interface.js' import { WSConnectionStatus } from '../../services/api/api.service.js' import chatService from '../../services/chat_service/chat_service.js' import { buildFakeMessage } from '../../services/chat_utils/chat_utils.js' @@ -17,6 +16,8 @@ import { isScrollable, } from './chat_layout_utils.js' +import { useInterfaceStore } from 'src/stores/interface.js' + import { library } from '@fortawesome/fontawesome-svg-core' import { faChevronDown, faChevronLeft } from '@fortawesome/free-solid-svg-icons' diff --git a/src/components/chat_list_item/chat_list_item.js b/src/components/chat_list_item/chat_list_item.js index 0923a8568..4f4ea4955 100644 --- a/src/components/chat_list_item/chat_list_item.js +++ b/src/components/chat_list_item/chat_list_item.js @@ -1,12 +1,13 @@ import { mapState } from 'vuex' -import fileType from 'src/services/file_type/file_type.service' import AvatarList from '../avatar_list/avatar_list.vue' import ChatTitle from '../chat_title/chat_title.vue' import StatusBody from '../status_content/status_content.vue' import Timeago from '../timeago/timeago.vue' import UserAvatar from '../user_avatar/user_avatar.vue' +import fileType from 'src/services/file_type/file_type.service' + const ChatListItem = { name: 'ChatListItem', props: ['chat'], diff --git a/src/components/chat_message/chat_message.js b/src/components/chat_message/chat_message.js index f3cc495c2..af3701ebf 100644 --- a/src/components/chat_message/chat_message.js +++ b/src/components/chat_message/chat_message.js @@ -2,7 +2,6 @@ import { mapState as mapPiniaState } from 'pinia' import { defineAsyncComponent } from 'vue' import { mapGetters, mapState } from 'vuex' -import { useInterfaceStore } from 'src/stores/interface' import Attachment from '../attachment/attachment.vue' import ChatMessageDate from '../chat_message_date/chat_message_date.vue' import Gallery from '../gallery/gallery.vue' @@ -11,6 +10,9 @@ import Popover from '../popover/popover.vue' import StatusContent from '../status_content/status_content.vue' import UserAvatar from '../user_avatar/user_avatar.vue' +import { useInstanceStore } from 'src/stores/instance.js' +import { useInterfaceStore } from 'src/stores/interface' + import { library } from '@fortawesome/fontawesome-svg-core' import { faEllipsisH, faTimes } from '@fortawesome/free-solid-svg-icons' @@ -74,7 +76,7 @@ const ChatMessage = { }), ...mapState({ currentUser: (state) => state.users.currentUser, - restrictedNicknames: (state) => state.instance.restrictedNicknames, + restrictedNicknames: (state) => useInstanceStore().restrictedNicknames, }), popoverMarginStyle() { if (this.isCurrentUser) { diff --git a/src/components/component_preview/component_preview.js b/src/components/component_preview/component_preview.js index 70696f56b..1d54f58de 100644 --- a/src/components/component_preview/component_preview.js +++ b/src/components/component_preview/component_preview.js @@ -1,5 +1,6 @@ import Checkbox from 'src/components/checkbox/checkbox.vue' import ColorInput from 'src/components/color_input/color_input.vue' + import genRandomSeed from 'src/services/random_seed/random_seed.service.js' import { adoptStyleSheets, diff --git a/src/components/conversation/conversation.js b/src/components/conversation/conversation.js index 3caf4add7..cb7cf4782 100644 --- a/src/components/conversation/conversation.js +++ b/src/components/conversation/conversation.js @@ -2,13 +2,14 @@ import { clone, filter, findIndex, get, reduce } from 'lodash' import { mapState as mapPiniaState } from 'pinia' import { mapGetters, mapState } from 'vuex' -import { useInterfaceStore } from 'src/stores/interface' import { WSConnectionStatus } from '../../services/api/api.service.js' import QuickFilterSettings from '../quick_filter_settings/quick_filter_settings.vue' import QuickViewSettings from '../quick_view_settings/quick_view_settings.vue' import Status from '../status/status.vue' import ThreadTree from '../thread_tree/thread_tree.vue' +import { useInterfaceStore } from 'src/stores/interface' + import { library } from '@fortawesome/fontawesome-svg-core' import { faAngleDoubleDown, diff --git a/src/components/desktop_nav/desktop_nav.js b/src/components/desktop_nav/desktop_nav.js index 8ab54b3df..a2c48ae53 100644 --- a/src/components/desktop_nav/desktop_nav.js +++ b/src/components/desktop_nav/desktop_nav.js @@ -1,8 +1,11 @@ import SearchBar from 'components/search_bar/search_bar.vue' +import { mapActions, mapState } from 'pinia' -import { useInterfaceStore } from 'src/stores/interface' import ConfirmModal from '../confirm_modal/confirm_modal.vue' +import { useInstanceStore } from 'src/stores/instance.js' +import { useInterfaceStore } from 'src/stores/interface' + import { library } from '@fortawesome/fontawesome-svg-core' import { faBell, @@ -51,7 +54,7 @@ export default { }), computed: { enableMask() { - return this.supportsMask && this.$store.state.instance.logoMask + return this.supportsMask && this.logoMask }, logoStyle() { return { @@ -61,7 +64,7 @@ export default { logoMaskStyle() { return this.enableMask ? { - 'mask-image': `url(${this.$store.state.instance.logo})`, + 'mask-image': `url(${this.logo})`, } : { 'background-color': this.enableMask ? '' : 'transparent', @@ -70,7 +73,7 @@ export default { logoBgStyle() { return Object.assign( { - margin: `${this.$store.state.instance.logoMargin} 0`, + margin: `${this.logoMargin} 0`, opacity: this.searchBarHidden ? 1 : 0, }, this.enableMask @@ -80,24 +83,18 @@ export default { }, ) }, - logo() { - return this.$store.state.instance.logo - }, - sitename() { - return this.$store.state.instance.name - }, - hideSitename() { - return this.$store.state.instance.hideSitename - }, - logoLeft() { - return this.$store.state.instance.logoLeft - }, + ...mapState(useInstanceStore, ['private']), + ...mapState(useInstanceStore, { + logoMask: (store) => store.instanceIdentity.logoMask, + logo: (store) => store.instanceIdentity.logo, + logoLeft: (store) => store.instanceIdentity.logoLeft, + logoMargin: (store) => store.instanceIdentity.logoMargin, + sitename: (store) => store.instanceIdentity.name, + hideSitename: (store) => store.instanceIdentity.hideSitename, + }), currentUser() { return this.$store.state.users.currentUser }, - privateMode() { - return this.$store.state.instance.private - }, shouldConfirmLogout() { return this.$store.getters.mergedConfig.modalOnLogout }, @@ -127,11 +124,6 @@ export default { onSearchBarToggled(hidden) { this.searchBarHidden = hidden }, - openSettingsModal() { - useInterfaceStore().openSettingsModal('user') - }, - openAdminModal() { - useInterfaceStore().openSettingsModal('admin') - }, + ...mapActions(useInterfaceStore, ['openSettingsModal']), }, } diff --git a/src/components/desktop_nav/desktop_nav.vue b/src/components/desktop_nav/desktop_nav.vue index 49382f8ee..da427f2a1 100644 --- a/src/components/desktop_nav/desktop_nav.vue +++ b/src/components/desktop_nav/desktop_nav.vue @@ -40,7 +40,7 @@