first pass of migration - states and obvious replacements
This commit is contained in:
parent
02f952047d
commit
24ce2dc0a5
66 changed files with 398 additions and 568 deletions
15
src/App.js
15
src/App.js
|
|
@ -2,6 +2,7 @@ import { throttle } from 'lodash'
|
||||||
import { defineAsyncComponent } from 'vue'
|
import { defineAsyncComponent } from 'vue'
|
||||||
import { mapGetters } from 'vuex'
|
import { mapGetters } from 'vuex'
|
||||||
|
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import DesktopNav from './components/desktop_nav/desktop_nav.vue'
|
import DesktopNav from './components/desktop_nav/desktop_nav.vue'
|
||||||
import EditStatusModal from './components/edit_status_modal/edit_status_modal.vue'
|
import EditStatusModal from './components/edit_status_modal/edit_status_modal.vue'
|
||||||
import FeaturesPanel from './components/features_panel/features_panel.vue'
|
import FeaturesPanel from './components/features_panel/features_panel.vue'
|
||||||
|
|
@ -136,7 +137,7 @@ export default {
|
||||||
instanceBackground() {
|
instanceBackground() {
|
||||||
return this.mergedConfig.hideInstanceWallpaper
|
return this.mergedConfig.hideInstanceWallpaper
|
||||||
? null
|
? null
|
||||||
: this.$store.state.instance.background
|
: useInstanceStore().background
|
||||||
},
|
},
|
||||||
background() {
|
background() {
|
||||||
return this.userBackground || this.instanceBackground
|
return this.userBackground || this.instanceBackground
|
||||||
|
|
@ -152,13 +153,13 @@ export default {
|
||||||
return useShoutStore().joined
|
return useShoutStore().joined
|
||||||
},
|
},
|
||||||
suggestionsEnabled() {
|
suggestionsEnabled() {
|
||||||
return this.$store.state.instance.suggestionsEnabled
|
return useInstanceStore().suggestionsEnabled
|
||||||
},
|
},
|
||||||
showInstanceSpecificPanel() {
|
showInstanceSpecificPanel() {
|
||||||
return (
|
return (
|
||||||
this.$store.state.instance.showInstanceSpecificPanel &&
|
useInstanceStore().showInstanceSpecificPanel &&
|
||||||
!this.$store.getters.mergedConfig.hideISP &&
|
!this.$store.getters.mergedConfig.hideISP &&
|
||||||
this.$store.state.instance.instanceSpecificPanelContent
|
useInstanceStore().instanceSpecificPanelContent
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
isChats() {
|
isChats() {
|
||||||
|
|
@ -176,10 +177,10 @@ export default {
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
showFeaturesPanel() {
|
showFeaturesPanel() {
|
||||||
return this.$store.state.instance.showFeaturesPanel
|
return useInstanceStore().showFeaturesPanel
|
||||||
},
|
},
|
||||||
editingAvailable() {
|
editingAvailable() {
|
||||||
return this.$store.state.instance.editingAvailable
|
return useInstanceStore().editingAvailable
|
||||||
},
|
},
|
||||||
shoutboxPosition() {
|
shoutboxPosition() {
|
||||||
return this.$store.getters.mergedConfig.alwaysShowNewPostButton || false
|
return this.$store.getters.mergedConfig.alwaysShowNewPostButton || false
|
||||||
|
|
@ -191,7 +192,7 @@ export default {
|
||||||
return useInterfaceStore().layoutType
|
return useInterfaceStore().layoutType
|
||||||
},
|
},
|
||||||
privateMode() {
|
privateMode() {
|
||||||
return this.$store.state.instance.private
|
return useInstanceStore().private
|
||||||
},
|
},
|
||||||
reverseLayout() {
|
reverseLayout() {
|
||||||
const { thirdColumnMode, sidebarRight: reverseSetting } =
|
const { thirdColumnMode, sidebarRight: reverseSetting } =
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ import UserProfile from 'components/user_profile/user_profile.vue'
|
||||||
import WhoToFollow from 'components/who_to_follow/who_to_follow.vue'
|
import WhoToFollow from 'components/who_to_follow/who_to_follow.vue'
|
||||||
|
|
||||||
import NavPanel from 'src/components/nav_panel/nav_panel.vue'
|
import NavPanel from 'src/components/nav_panel/nav_panel.vue'
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import BookmarkFolderEdit from '../components/bookmark_folder_edit/bookmark_folder_edit.vue'
|
import BookmarkFolderEdit from '../components/bookmark_folder_edit/bookmark_folder_edit.vue'
|
||||||
import BookmarkFolders from '../components/bookmark_folders/bookmark_folders.vue'
|
import BookmarkFolders from '../components/bookmark_folders/bookmark_folders.vue'
|
||||||
import QuotesTimeline from '../components/quotes_timeline/quotes_timeline.vue'
|
import QuotesTimeline from '../components/quotes_timeline/quotes_timeline.vue'
|
||||||
|
|
@ -37,7 +38,7 @@ export default (store) => {
|
||||||
if (store.state.users.currentUser) {
|
if (store.state.users.currentUser) {
|
||||||
next()
|
next()
|
||||||
} else {
|
} else {
|
||||||
next(store.state.instance.redirectRootNoLogin || '/main/all')
|
next(useInstanceStore().redirectRootNoLogin || '/main/all')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -48,8 +49,8 @@ export default (store) => {
|
||||||
redirect: () => {
|
redirect: () => {
|
||||||
return (
|
return (
|
||||||
(store.state.users.currentUser
|
(store.state.users.currentUser
|
||||||
? store.state.instance.redirectRootLogin
|
? useInstanceStore().redirectRootLogin
|
||||||
: store.state.instance.redirectRootNoLogin) || '/main/all'
|
: useInstanceStore().redirectRootNoLogin) || '/main/all'
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -200,7 +201,7 @@ export default (store) => {
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
if (store.state.instance.pleromaChatMessagesAvailable) {
|
if (useInstanceStore().pleromaChatMessagesAvailable) {
|
||||||
routes = routes.concat([
|
routes = routes.concat([
|
||||||
{
|
{
|
||||||
name: 'chat',
|
name: 'chat',
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import FeaturesPanel from '../features_panel/features_panel.vue'
|
import FeaturesPanel from '../features_panel/features_panel.vue'
|
||||||
import InstanceSpecificPanel from '../instance_specific_panel/instance_specific_panel.vue'
|
import InstanceSpecificPanel from '../instance_specific_panel/instance_specific_panel.vue'
|
||||||
import MRFTransparencyPanel from '../mrf_transparency_panel/mrf_transparency_panel.vue'
|
import MRFTransparencyPanel from '../mrf_transparency_panel/mrf_transparency_panel.vue'
|
||||||
|
|
@ -14,13 +15,13 @@ const About = {
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
showFeaturesPanel() {
|
showFeaturesPanel() {
|
||||||
return this.$store.state.instance.showFeaturesPanel
|
return useInstanceStore().showFeaturesPanel
|
||||||
},
|
},
|
||||||
showInstanceSpecificPanel() {
|
showInstanceSpecificPanel() {
|
||||||
return (
|
return (
|
||||||
this.$store.state.instance.showInstanceSpecificPanel &&
|
useInstanceStore().showInstanceSpecificPanel &&
|
||||||
!this.$store.getters.mergedConfig.hideISP &&
|
!this.$store.getters.mergedConfig.hideISP &&
|
||||||
this.$store.state.instance.instanceSpecificPanelContent
|
useInstanceStore().instanceSpecificPanelContent
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import { mapState } from 'vuex'
|
||||||
|
|
||||||
import UserListMenu from 'src/components/user_list_menu/user_list_menu.vue'
|
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 UserTimedFilterModal from 'src/components/user_timed_filter_modal/user_timed_filter_modal.vue'
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import { useReportsStore } from 'src/stores/reports'
|
import { useReportsStore } from 'src/stores/reports'
|
||||||
import ConfirmModal from '../confirm_modal/confirm_modal.vue'
|
import ConfirmModal from '../confirm_modal/confirm_modal.vue'
|
||||||
import Popover from '../popover/popover.vue'
|
import Popover from '../popover/popover.vue'
|
||||||
|
|
@ -93,9 +94,9 @@ const AccountActions = {
|
||||||
return this.$store.getters.mergedConfig.modalOnRemoveUserFromFollowers
|
return this.$store.getters.mergedConfig.modalOnRemoveUserFromFollowers
|
||||||
},
|
},
|
||||||
...mapState({
|
...mapState({
|
||||||
blockExpirationSupported: (state) => state.instance.blockExpiration,
|
blockExpirationSupported: (state) => useInstanceStore().blockExpiration,
|
||||||
pleromaChatMessagesAvailable: (state) =>
|
pleromaChatMessagesAvailable: (state) =>
|
||||||
state.instance.pleromaChatMessagesAvailable,
|
useInstanceStore().pleromaChatMessagesAvailable,
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import { mapGetters } from 'vuex'
|
import { mapGetters } from 'vuex'
|
||||||
|
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import { useMediaViewerStore } from 'src/stores/media_viewer'
|
import { useMediaViewerStore } from 'src/stores/media_viewer'
|
||||||
import nsfwImage from '../../assets/nsfw.png'
|
import nsfwImage from '../../assets/nsfw.png'
|
||||||
import fileTypeService from '../../services/file_type/file_type.service.js'
|
import fileTypeService from '../../services/file_type/file_type.service.js'
|
||||||
|
|
@ -53,7 +54,7 @@ const Attachment = {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
localDescription: this.description || this.attachment.description,
|
localDescription: this.description || this.attachment.description,
|
||||||
nsfwImage: this.$store.state.instance.nsfwCensorImage || nsfwImage,
|
nsfwImage: useInstanceStore().nsfwCensorImage || nsfwImage,
|
||||||
hideNsfwLocal: this.$store.getters.mergedConfig.hideNsfw,
|
hideNsfwLocal: this.$store.getters.mergedConfig.hideNsfw,
|
||||||
preloadImage: this.$store.getters.mergedConfig.preloadImage,
|
preloadImage: this.$store.getters.mergedConfig.preloadImage,
|
||||||
loading: false,
|
loading: false,
|
||||||
|
|
@ -104,7 +105,7 @@ const Attachment = {
|
||||||
return 'file'
|
return 'file'
|
||||||
},
|
},
|
||||||
referrerpolicy() {
|
referrerpolicy() {
|
||||||
return this.$store.state.instance.mediaProxyAvailable ? '' : 'no-referrer'
|
return useInstanceStore().mediaProxyAvailable ? '' : 'no-referrer'
|
||||||
},
|
},
|
||||||
type() {
|
type() {
|
||||||
return fileTypeService.fileType(this.attachment.mimetype)
|
return fileTypeService.fileType(this.attachment.mimetype)
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
|
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import UserAvatar from '../user_avatar/user_avatar.vue'
|
import UserAvatar from '../user_avatar/user_avatar.vue'
|
||||||
|
|
||||||
const AvatarList = {
|
const AvatarList = {
|
||||||
|
|
@ -16,7 +17,7 @@ const AvatarList = {
|
||||||
return generateProfileLink(
|
return generateProfileLink(
|
||||||
user.id,
|
user.id,
|
||||||
user.screen_name,
|
user.screen_name,
|
||||||
this.$store.state.instance.restrictedNicknames,
|
useInstanceStore().restrictedNicknames,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import RichContent from 'src/components/rich_content/rich_content.jsx'
|
import RichContent from 'src/components/rich_content/rich_content.jsx'
|
||||||
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
|
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import UserAvatar from '../user_avatar/user_avatar.vue'
|
import UserAvatar from '../user_avatar/user_avatar.vue'
|
||||||
import UserLink from '../user_link/user_link.vue'
|
import UserLink from '../user_link/user_link.vue'
|
||||||
import UserPopover from '../user_popover/user_popover.vue'
|
import UserPopover from '../user_popover/user_popover.vue'
|
||||||
|
|
@ -17,7 +18,7 @@ const BasicUserCard = {
|
||||||
return generateProfileLink(
|
return generateProfileLink(
|
||||||
user.id,
|
user.id,
|
||||||
user.screen_name,
|
user.screen_name,
|
||||||
this.$store.state.instance.restrictedNicknames,
|
useInstanceStore().restrictedNicknames,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import { mapState } from 'vuex'
|
import { mapState } from 'pinia'
|
||||||
|
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import BasicUserCard from '../basic_user_card/basic_user_card.vue'
|
import BasicUserCard from '../basic_user_card/basic_user_card.vue'
|
||||||
|
|
||||||
const BlockCard = {
|
const BlockCard = {
|
||||||
|
|
@ -25,7 +26,7 @@ const BlockCard = {
|
||||||
])
|
])
|
||||||
},
|
},
|
||||||
...mapState({
|
...mapState({
|
||||||
blockExpirationSupported: (state) => state.instance.blockExpiration,
|
blockExpirationSupported: (store) => store.blockExpiration,
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import { mapState as mapPiniaState } from 'pinia'
|
||||||
import { defineAsyncComponent } from 'vue'
|
import { defineAsyncComponent } from 'vue'
|
||||||
import { mapGetters, mapState } from 'vuex'
|
import { mapGetters, mapState } from 'vuex'
|
||||||
|
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import { useInterfaceStore } from 'src/stores/interface'
|
import { useInterfaceStore } from 'src/stores/interface'
|
||||||
import Attachment from '../attachment/attachment.vue'
|
import Attachment from '../attachment/attachment.vue'
|
||||||
import ChatMessageDate from '../chat_message_date/chat_message_date.vue'
|
import ChatMessageDate from '../chat_message_date/chat_message_date.vue'
|
||||||
|
|
@ -74,7 +75,7 @@ const ChatMessage = {
|
||||||
}),
|
}),
|
||||||
...mapState({
|
...mapState({
|
||||||
currentUser: (state) => state.users.currentUser,
|
currentUser: (state) => state.users.currentUser,
|
||||||
restrictedNicknames: (state) => state.instance.restrictedNicknames,
|
restrictedNicknames: (state) => useInstanceStore().restrictedNicknames,
|
||||||
}),
|
}),
|
||||||
popoverMarginStyle() {
|
popoverMarginStyle() {
|
||||||
if (this.isCurrentUser) {
|
if (this.isCurrentUser) {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import SearchBar from 'components/search_bar/search_bar.vue'
|
import SearchBar from 'components/search_bar/search_bar.vue'
|
||||||
|
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import { useInterfaceStore } from 'src/stores/interface'
|
import { useInterfaceStore } from 'src/stores/interface'
|
||||||
import ConfirmModal from '../confirm_modal/confirm_modal.vue'
|
import ConfirmModal from '../confirm_modal/confirm_modal.vue'
|
||||||
|
|
||||||
|
|
@ -51,7 +52,7 @@ export default {
|
||||||
}),
|
}),
|
||||||
computed: {
|
computed: {
|
||||||
enableMask() {
|
enableMask() {
|
||||||
return this.supportsMask && this.$store.state.instance.logoMask
|
return this.supportsMask && useInstanceStore().logoMask
|
||||||
},
|
},
|
||||||
logoStyle() {
|
logoStyle() {
|
||||||
return {
|
return {
|
||||||
|
|
@ -61,7 +62,7 @@ export default {
|
||||||
logoMaskStyle() {
|
logoMaskStyle() {
|
||||||
return this.enableMask
|
return this.enableMask
|
||||||
? {
|
? {
|
||||||
'mask-image': `url(${this.$store.state.instance.logo})`,
|
'mask-image': `url(${useInstanceStore().logo})`,
|
||||||
}
|
}
|
||||||
: {
|
: {
|
||||||
'background-color': this.enableMask ? '' : 'transparent',
|
'background-color': this.enableMask ? '' : 'transparent',
|
||||||
|
|
@ -70,7 +71,7 @@ export default {
|
||||||
logoBgStyle() {
|
logoBgStyle() {
|
||||||
return Object.assign(
|
return Object.assign(
|
||||||
{
|
{
|
||||||
margin: `${this.$store.state.instance.logoMargin} 0`,
|
margin: `${useInstanceStore().logoMargin} 0`,
|
||||||
opacity: this.searchBarHidden ? 1 : 0,
|
opacity: this.searchBarHidden ? 1 : 0,
|
||||||
},
|
},
|
||||||
this.enableMask
|
this.enableMask
|
||||||
|
|
@ -81,22 +82,22 @@ export default {
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
logo() {
|
logo() {
|
||||||
return this.$store.state.instance.logo
|
return useInstanceStore().logo
|
||||||
},
|
},
|
||||||
sitename() {
|
sitename() {
|
||||||
return this.$store.state.instance.name
|
return useInstanceStore().name
|
||||||
},
|
},
|
||||||
hideSitename() {
|
hideSitename() {
|
||||||
return this.$store.state.instance.hideSitename
|
return useInstanceStore().hideSitename
|
||||||
},
|
},
|
||||||
logoLeft() {
|
logoLeft() {
|
||||||
return this.$store.state.instance.logoLeft
|
return useInstanceStore().logoLeft
|
||||||
},
|
},
|
||||||
currentUser() {
|
currentUser() {
|
||||||
return this.$store.state.users.currentUser
|
return this.$store.state.users.currentUser
|
||||||
},
|
},
|
||||||
privateMode() {
|
privateMode() {
|
||||||
return this.$store.state.instance.private
|
return useInstanceStore().private
|
||||||
},
|
},
|
||||||
shouldConfirmLogout() {
|
shouldConfirmLogout() {
|
||||||
return this.$store.getters.mergedConfig.modalOnLogout
|
return this.$store.getters.mergedConfig.modalOnLogout
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import { chunk, debounce, trim } from 'lodash'
|
||||||
import { defineAsyncComponent } from 'vue'
|
import { defineAsyncComponent } from 'vue'
|
||||||
|
|
||||||
import Popover from 'src/components/popover/popover.vue'
|
import Popover from 'src/components/popover/popover.vue'
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import { ensureFinalFallback } from '../../i18n/languages.js'
|
import { ensureFinalFallback } from '../../i18n/languages.js'
|
||||||
import Checkbox from '../checkbox/checkbox.vue'
|
import Checkbox from '../checkbox/checkbox.vue'
|
||||||
import StillImage from '../still-image/still-image.vue'
|
import StillImage from '../still-image/still-image.vue'
|
||||||
|
|
@ -349,8 +350,8 @@ const EmojiPicker = {
|
||||||
return this.showingStickers ? '' : this.activeGroup
|
return this.showingStickers ? '' : this.activeGroup
|
||||||
},
|
},
|
||||||
stickersAvailable() {
|
stickersAvailable() {
|
||||||
if (this.$store.state.instance.stickers) {
|
if (useInstanceStore().stickers) {
|
||||||
return this.$store.state.instance.stickers.length > 0
|
return useInstanceStore().stickers.length > 0
|
||||||
}
|
}
|
||||||
return 0
|
return 0
|
||||||
},
|
},
|
||||||
|
|
@ -381,7 +382,7 @@ const EmojiPicker = {
|
||||||
.concat(this.unicodeEmojiGroups)
|
.concat(this.unicodeEmojiGroups)
|
||||||
},
|
},
|
||||||
stickerPickerEnabled() {
|
stickerPickerEnabled() {
|
||||||
return (this.$store.state.instance.stickers || []).length !== 0
|
return (useInstanceStore().stickers || []).length !== 0
|
||||||
},
|
},
|
||||||
debouncedHandleKeywordChange() {
|
debouncedHandleKeywordChange() {
|
||||||
return debounce(() => {
|
return debounce(() => {
|
||||||
|
|
|
||||||
|
|
@ -1,31 +1,32 @@
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import fileSizeFormatService from '../../services/file_size_format/file_size_format.js'
|
import fileSizeFormatService from '../../services/file_size_format/file_size_format.js'
|
||||||
|
|
||||||
const FeaturesPanel = {
|
const FeaturesPanel = {
|
||||||
computed: {
|
computed: {
|
||||||
shout: function () {
|
shout: function () {
|
||||||
return this.$store.state.instance.shoutAvailable
|
return useInstanceStore().shoutAvailable
|
||||||
},
|
},
|
||||||
pleromaChatMessages: function () {
|
pleromaChatMessages: function () {
|
||||||
return this.$store.state.instance.pleromaChatMessagesAvailable
|
return useInstanceStore().pleromaChatMessagesAvailable
|
||||||
},
|
},
|
||||||
gopher: function () {
|
gopher: function () {
|
||||||
return this.$store.state.instance.gopherAvailable
|
return useInstanceStore().gopherAvailable
|
||||||
},
|
},
|
||||||
whoToFollow: function () {
|
whoToFollow: function () {
|
||||||
return this.$store.state.instance.suggestionsEnabled
|
return useInstanceStore().suggestionsEnabled
|
||||||
},
|
},
|
||||||
mediaProxy: function () {
|
mediaProxy: function () {
|
||||||
return this.$store.state.instance.mediaProxyAvailable
|
return useInstanceStore().mediaProxyAvailable
|
||||||
},
|
},
|
||||||
minimalScopesMode: function () {
|
minimalScopesMode: function () {
|
||||||
return this.$store.state.instance.minimalScopesMode
|
return useInstanceStore().minimalScopesMode
|
||||||
},
|
},
|
||||||
textlimit: function () {
|
textlimit: function () {
|
||||||
return this.$store.state.instance.textlimit
|
return useInstanceStore().textlimit
|
||||||
},
|
},
|
||||||
uploadlimit: function () {
|
uploadlimit: function () {
|
||||||
return fileSizeFormatService.fileSizeFormat(
|
return fileSizeFormatService.fileSizeFormat(
|
||||||
this.$store.state.instance.uploadlimit,
|
useInstanceStore().uploadlimit,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
|
|
||||||
const InstanceSpecificPanel = {
|
const InstanceSpecificPanel = {
|
||||||
computed: {
|
computed: {
|
||||||
instanceSpecificPanelContent() {
|
instanceSpecificPanelContent() {
|
||||||
return this.$store.state.instance.instanceSpecificPanelContent
|
return useInstanceStore().instanceSpecificPanelContent
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import { mapState } from 'vuex'
|
||||||
|
|
||||||
import { getListEntries } from 'src/components/navigation/filter.js'
|
import { getListEntries } from 'src/components/navigation/filter.js'
|
||||||
import NavigationEntry from 'src/components/navigation/navigation_entry.vue'
|
import NavigationEntry from 'src/components/navigation/navigation_entry.vue'
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import { useListsStore } from 'src/stores/lists'
|
import { useListsStore } from 'src/stores/lists'
|
||||||
|
|
||||||
export const ListsMenuContent = {
|
export const ListsMenuContent = {
|
||||||
|
|
@ -16,8 +17,8 @@ export const ListsMenuContent = {
|
||||||
}),
|
}),
|
||||||
...mapState({
|
...mapState({
|
||||||
currentUser: (state) => state.users.currentUser,
|
currentUser: (state) => state.users.currentUser,
|
||||||
privateMode: (state) => state.instance.private,
|
privateMode: (state) => useInstanceStore().private,
|
||||||
federating: (state) => state.instance.federating,
|
federating: (state) => useInstanceStore().federating,
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import { mapActions, mapState as mapPiniaState, mapStores } from 'pinia'
|
||||||
import { mapState } from 'vuex'
|
import { mapState } from 'vuex'
|
||||||
|
|
||||||
import { useAuthFlowStore } from 'src/stores/auth_flow.js'
|
import { useAuthFlowStore } from 'src/stores/auth_flow.js'
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import { useOAuthStore } from 'src/stores/oauth.js'
|
import { useOAuthStore } from 'src/stores/oauth.js'
|
||||||
import oauthApi from '../../services/new_api/oauth.js'
|
import oauthApi from '../../services/new_api/oauth.js'
|
||||||
|
|
||||||
|
|
@ -24,8 +25,8 @@ const LoginForm = {
|
||||||
},
|
},
|
||||||
...mapStores(useOAuthStore),
|
...mapStores(useOAuthStore),
|
||||||
...mapState({
|
...mapState({
|
||||||
registrationOpen: (state) => state.instance.registrationOpen,
|
registrationOpen: (state) => useInstanceStore().registrationOpen,
|
||||||
instance: (state) => state.instance,
|
instance: (state) => useInstanceStore(),
|
||||||
loggingIn: (state) => state.users.loggingIn,
|
loggingIn: (state) => state.users.loggingIn,
|
||||||
}),
|
}),
|
||||||
...mapPiniaState(useAuthFlowStore, [
|
...mapPiniaState(useAuthFlowStore, [
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
/* eslint-env browser */
|
|
||||||
|
|
||||||
import fileSizeFormatService from '../../services/file_size_format/file_size_format.js'
|
import fileSizeFormatService from '../../services/file_size_format/file_size_format.js'
|
||||||
import statusPosterService from '../../services/status_poster/status_poster.service.js'
|
import statusPosterService from '../../services/status_poster/status_poster.service.js'
|
||||||
|
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
|
|
||||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||||
import { faCircleNotch, faUpload } from '@fortawesome/free-solid-svg-icons'
|
import { faCircleNotch, faUpload } from '@fortawesome/free-solid-svg-icons'
|
||||||
|
|
||||||
|
|
@ -122,10 +122,10 @@ const mediaUpload = {
|
||||||
async uploadFile(file) {
|
async uploadFile(file) {
|
||||||
const self = this
|
const self = this
|
||||||
const store = this.$store
|
const store = this.$store
|
||||||
if (file.size > store.state.instance.uploadlimit) {
|
if (file.size > useInstanceStore().uploadlimit) {
|
||||||
const filesize = fileSizeFormatService.fileSizeFormat(file.size)
|
const filesize = fileSizeFormatService.fileSizeFormat(file.size)
|
||||||
const allowedsize = fileSizeFormatService.fileSizeFormat(
|
const allowedsize = fileSizeFormatService.fileSizeFormat(
|
||||||
store.state.instance.uploadlimit,
|
useInstanceStore().uploadlimit,
|
||||||
)
|
)
|
||||||
self.$emit('upload-failed', 'file_too_big', {
|
self.$emit('upload-failed', 'file_too_big', {
|
||||||
filesize: filesize.num,
|
filesize: filesize.num,
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import { mapGetters } from 'vuex'
|
||||||
|
|
||||||
import NavigationPins from 'src/components/navigation/navigation_pins.vue'
|
import NavigationPins from 'src/components/navigation/navigation_pins.vue'
|
||||||
import { useAnnouncementsStore } from 'src/stores/announcements'
|
import { useAnnouncementsStore } from 'src/stores/announcements'
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import { useServerSideStorageStore } from 'src/stores/serverSideStorage'
|
import { useServerSideStorageStore } from 'src/stores/serverSideStorage'
|
||||||
import GestureService from '../../services/gesture_service/gesture_service'
|
import GestureService from '../../services/gesture_service/gesture_service'
|
||||||
import {
|
import {
|
||||||
|
|
@ -64,10 +65,10 @@ const MobileNav = {
|
||||||
return `${this.unseenCount ? this.unseenCount : ''}`
|
return `${this.unseenCount ? this.unseenCount : ''}`
|
||||||
},
|
},
|
||||||
hideSitename() {
|
hideSitename() {
|
||||||
return this.$store.state.instance.hideSitename
|
return useInstanceStore().hideSitename
|
||||||
},
|
},
|
||||||
sitename() {
|
sitename() {
|
||||||
return this.$store.state.instance.name
|
return useInstanceStore().name
|
||||||
},
|
},
|
||||||
isChat() {
|
isChat() {
|
||||||
return this.$route.name === 'chat'
|
return this.$route.name === 'chat'
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import DialogModal from '../dialog_modal/dialog_modal.vue'
|
import DialogModal from '../dialog_modal/dialog_modal.vue'
|
||||||
import Popover from '../popover/popover.vue'
|
import Popover from '../popover/popover.vue'
|
||||||
|
|
||||||
|
|
@ -54,7 +55,7 @@ const ModerationTools = {
|
||||||
},
|
},
|
||||||
canUseTagPolicy() {
|
canUseTagPolicy() {
|
||||||
return (
|
return (
|
||||||
this.$store.state.instance.tagPolicyAvailable &&
|
useInstanceStore().tagPolicyAvailable &&
|
||||||
this.privileged('users_manage_tags')
|
this.privileged('users_manage_tags')
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import { ROOT_ITEMS, TIMELINES } from 'src/components/navigation/navigation.js'
|
||||||
import NavigationEntry from 'src/components/navigation/navigation_entry.vue'
|
import NavigationEntry from 'src/components/navigation/navigation_entry.vue'
|
||||||
import NavigationPins from 'src/components/navigation/navigation_pins.vue'
|
import NavigationPins from 'src/components/navigation/navigation_pins.vue'
|
||||||
import { useAnnouncementsStore } from 'src/stores/announcements'
|
import { useAnnouncementsStore } from 'src/stores/announcements'
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import { useServerSideStorageStore } from 'src/stores/serverSideStorage'
|
import { useServerSideStorageStore } from 'src/stores/serverSideStorage'
|
||||||
|
|
||||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||||
|
|
@ -118,13 +119,14 @@ const NavPanel = {
|
||||||
...mapState({
|
...mapState({
|
||||||
currentUser: (state) => state.users.currentUser,
|
currentUser: (state) => state.users.currentUser,
|
||||||
followRequestCount: (state) => state.api.followRequests.length,
|
followRequestCount: (state) => state.api.followRequests.length,
|
||||||
privateMode: (state) => state.instance.private,
|
privateMode: (state) => useInstanceStore().private,
|
||||||
federating: (state) => state.instance.federating,
|
federating: (state) => useInstanceStore().federating,
|
||||||
pleromaChatMessagesAvailable: (state) =>
|
pleromaChatMessagesAvailable: (state) =>
|
||||||
state.instance.pleromaChatMessagesAvailable,
|
useInstanceStore().pleromaChatMessagesAvailable,
|
||||||
bookmarkFolders: (state) =>
|
bookmarkFolders: (state) =>
|
||||||
state.instance.pleromaBookmarkFoldersAvailable,
|
useInstanceStore().pleromaBookmarkFoldersAvailable,
|
||||||
bubbleTimeline: (state) => state.instance.localBubbleInstances.length > 0,
|
bubbleTimeline: (state) =>
|
||||||
|
useInstanceStore().localBubbleInstances.length > 0,
|
||||||
}),
|
}),
|
||||||
timelinesItems() {
|
timelinesItems() {
|
||||||
return filterNavigation(
|
return filterNavigation(
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ import {
|
||||||
import StillImage from 'src/components/still-image/still-image.vue'
|
import StillImage from 'src/components/still-image/still-image.vue'
|
||||||
import { useAnnouncementsStore } from 'src/stores/announcements'
|
import { useAnnouncementsStore } from 'src/stores/announcements'
|
||||||
import { useBookmarkFoldersStore } from 'src/stores/bookmark_folders'
|
import { useBookmarkFoldersStore } from 'src/stores/bookmark_folders'
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import { useListsStore } from 'src/stores/lists'
|
import { useListsStore } from 'src/stores/lists'
|
||||||
import { useServerSideStorageStore } from 'src/stores/serverSideStorage'
|
import { useServerSideStorageStore } from 'src/stores/serverSideStorage'
|
||||||
|
|
||||||
|
|
@ -74,11 +75,12 @@ const NavPanel = {
|
||||||
...mapState({
|
...mapState({
|
||||||
currentUser: (state) => state.users.currentUser,
|
currentUser: (state) => state.users.currentUser,
|
||||||
followRequestCount: (state) => state.api.followRequests.length,
|
followRequestCount: (state) => state.api.followRequests.length,
|
||||||
privateMode: (state) => state.instance.private,
|
privateMode: (state) => useInstanceStore().private,
|
||||||
federating: (state) => state.instance.federating,
|
federating: (state) => useInstanceStore().federating,
|
||||||
pleromaChatMessagesAvailable: (state) =>
|
pleromaChatMessagesAvailable: (state) =>
|
||||||
state.instance.pleromaChatMessagesAvailable,
|
useInstanceStore().pleromaChatMessagesAvailable,
|
||||||
bubbleTimeline: (state) => state.instance.localBubbleInstances.length > 0,
|
bubbleTimeline: (state) =>
|
||||||
|
useInstanceStore().localBubbleInstances.length > 0,
|
||||||
}),
|
}),
|
||||||
pinnedList() {
|
pinnedList() {
|
||||||
if (!this.currentUser) {
|
if (!this.currentUser) {
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import { mapState } from 'vuex'
|
||||||
|
|
||||||
import RichContent from 'src/components/rich_content/rich_content.jsx'
|
import RichContent from 'src/components/rich_content/rich_content.jsx'
|
||||||
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
|
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import { isStatusNotification } from '../../services/notification_utils/notification_utils.js'
|
import { isStatusNotification } from '../../services/notification_utils/notification_utils.js'
|
||||||
import {
|
import {
|
||||||
highlightClass,
|
highlightClass,
|
||||||
|
|
@ -107,7 +108,7 @@ const Notification = {
|
||||||
return generateProfileLink(
|
return generateProfileLink(
|
||||||
user.id,
|
user.id,
|
||||||
user.screen_name,
|
user.screen_name,
|
||||||
this.$store.state.instance.restrictedNicknames,
|
useInstanceStore().restrictedNicknames,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
getUser(notification) {
|
getUser(notification) {
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import { useOAuthStore } from 'src/stores/oauth.js'
|
import { useOAuthStore } from 'src/stores/oauth.js'
|
||||||
import oauth from '../../services/new_api/oauth.js'
|
import oauth from '../../services/new_api/oauth.js'
|
||||||
|
|
||||||
|
|
@ -12,7 +13,7 @@ const oac = {
|
||||||
.getToken({
|
.getToken({
|
||||||
clientId,
|
clientId,
|
||||||
clientSecret,
|
clientSecret,
|
||||||
instance: this.$store.state.instance.server,
|
instance: useInstanceStore().server,
|
||||||
code: this.code,
|
code: this.code,
|
||||||
})
|
})
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
|
import { mapState as mapPiniaState } from 'pinia'
|
||||||
import { mapState } from 'vuex'
|
import { mapState } from 'vuex'
|
||||||
|
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import passwordResetApi from '../../services/new_api/password_reset.js'
|
import passwordResetApi from '../../services/new_api/password_reset.js'
|
||||||
|
|
||||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||||
|
|
@ -20,8 +22,8 @@ const passwordReset = {
|
||||||
computed: {
|
computed: {
|
||||||
...mapState({
|
...mapState({
|
||||||
signedIn: (state) => !!state.users.currentUser,
|
signedIn: (state) => !!state.users.currentUser,
|
||||||
instance: (state) => state.instance,
|
|
||||||
}),
|
}),
|
||||||
|
...mapPiniaState(useInstanceStore, ['server']),
|
||||||
mailerEnabled() {
|
mailerEnabled() {
|
||||||
return this.instance.mailerEnabled
|
return this.instance.mailerEnabled
|
||||||
},
|
},
|
||||||
|
|
@ -44,9 +46,9 @@ const passwordReset = {
|
||||||
submit() {
|
submit() {
|
||||||
this.isPending = true
|
this.isPending = true
|
||||||
const email = this.user.email
|
const email = this.user.email
|
||||||
const instance = this.instance.server
|
const server = this.server
|
||||||
|
|
||||||
passwordResetApi({ instance, email })
|
passwordResetApi({ server, email })
|
||||||
.then(({ status }) => {
|
.then(({ status }) => {
|
||||||
this.isPending = false
|
this.isPending = false
|
||||||
this.user.email = ''
|
this.user.email = ''
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import * as DateUtils from 'src/services/date_utils/date_utils.js'
|
import * as DateUtils from 'src/services/date_utils/date_utils.js'
|
||||||
import { pollFallback } from 'src/services/poll/poll.service.js'
|
import { pollFallback } from 'src/services/poll/poll.service.js'
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import Select from '../select/select.vue'
|
import Select from '../select/select.vue'
|
||||||
|
|
||||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||||
|
|
@ -52,7 +53,7 @@ export default {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
pollLimits() {
|
pollLimits() {
|
||||||
return this.$store.state.instance.pollLimits
|
return useInstanceStore().pollLimits
|
||||||
},
|
},
|
||||||
maxOptions() {
|
maxOptions() {
|
||||||
return this.pollLimits.max_options
|
return this.pollLimits.max_options
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import DraftCloser from 'src/components/draft_closer/draft_closer.vue'
|
||||||
import Gallery from 'src/components/gallery/gallery.vue'
|
import Gallery from 'src/components/gallery/gallery.vue'
|
||||||
import Popover from 'src/components/popover/popover.vue'
|
import Popover from 'src/components/popover/popover.vue'
|
||||||
import { pollFormToMasto } from 'src/services/poll/poll.service.js'
|
import { pollFormToMasto } from 'src/services/poll/poll.service.js'
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import { useInterfaceStore } from 'src/stores/interface.js'
|
import { useInterfaceStore } from 'src/stores/interface.js'
|
||||||
import { useMediaViewerStore } from 'src/stores/media_viewer.js'
|
import { useMediaViewerStore } from 'src/stores/media_viewer.js'
|
||||||
import { propsToNative } from '../../services/attributes_helper/attributes_helper.service.js'
|
import { propsToNative } from '../../services/attributes_helper/attributes_helper.service.js'
|
||||||
|
|
@ -259,7 +260,7 @@ const PostStatusForm = {
|
||||||
return suggestor({
|
return suggestor({
|
||||||
emoji: [
|
emoji: [
|
||||||
...this.$store.getters.standardEmojiList,
|
...this.$store.getters.standardEmojiList,
|
||||||
...this.$store.state.instance.customEmoji,
|
...useInstanceStore().customEmoji,
|
||||||
],
|
],
|
||||||
store: this.$store,
|
store: this.$store,
|
||||||
})
|
})
|
||||||
|
|
@ -268,7 +269,7 @@ const PostStatusForm = {
|
||||||
return suggestor({
|
return suggestor({
|
||||||
emoji: [
|
emoji: [
|
||||||
...this.$store.getters.standardEmojiList,
|
...this.$store.getters.standardEmojiList,
|
||||||
...this.$store.state.instance.customEmoji,
|
...useInstanceStore().customEmoji,
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
@ -276,7 +277,7 @@ const PostStatusForm = {
|
||||||
return this.$store.getters.standardEmojiList || []
|
return this.$store.getters.standardEmojiList || []
|
||||||
},
|
},
|
||||||
customEmoji() {
|
customEmoji() {
|
||||||
return this.$store.state.instance.customEmoji || []
|
return useInstanceStore().customEmoji || []
|
||||||
},
|
},
|
||||||
statusLength() {
|
statusLength() {
|
||||||
return this.newStatus.status.length
|
return this.newStatus.status.length
|
||||||
|
|
@ -285,7 +286,7 @@ const PostStatusForm = {
|
||||||
return this.newStatus.spoilerText.length
|
return this.newStatus.spoilerText.length
|
||||||
},
|
},
|
||||||
statusLengthLimit() {
|
statusLengthLimit() {
|
||||||
return this.$store.state.instance.textlimit
|
return useInstanceStore().textlimit
|
||||||
},
|
},
|
||||||
hasStatusLengthLimit() {
|
hasStatusLengthLimit() {
|
||||||
return this.statusLengthLimit > 0
|
return this.statusLengthLimit > 0
|
||||||
|
|
@ -299,21 +300,21 @@ const PostStatusForm = {
|
||||||
return this.hasStatusLengthLimit && this.charactersLeft < 0
|
return this.hasStatusLengthLimit && this.charactersLeft < 0
|
||||||
},
|
},
|
||||||
minimalScopesMode() {
|
minimalScopesMode() {
|
||||||
return this.$store.state.instance.minimalScopesMode
|
return useInstanceStore().minimalScopesMode
|
||||||
},
|
},
|
||||||
alwaysShowSubject() {
|
alwaysShowSubject() {
|
||||||
return this.mergedConfig.alwaysShowSubjectInput
|
return this.mergedConfig.alwaysShowSubjectInput
|
||||||
},
|
},
|
||||||
postFormats() {
|
postFormats() {
|
||||||
return this.$store.state.instance.postFormats || []
|
return useInstanceStore().postFormats || []
|
||||||
},
|
},
|
||||||
safeDMEnabled() {
|
safeDMEnabled() {
|
||||||
return this.$store.state.instance.safeDM
|
return useInstanceStore().safeDM
|
||||||
},
|
},
|
||||||
pollsAvailable() {
|
pollsAvailable() {
|
||||||
return (
|
return (
|
||||||
this.$store.state.instance.pollsAvailable &&
|
useInstanceStore().pollsAvailable &&
|
||||||
this.$store.state.instance.pollLimits.max_options >= 2 &&
|
useInstanceStore().pollLimits.max_options >= 2 &&
|
||||||
this.disablePolls !== true
|
this.disablePolls !== true
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
@ -342,7 +343,7 @@ const PostStatusForm = {
|
||||||
return typeof this.statusId !== 'undefined' && this.statusId.trim() !== ''
|
return typeof this.statusId !== 'undefined' && this.statusId.trim() !== ''
|
||||||
},
|
},
|
||||||
quotable() {
|
quotable() {
|
||||||
if (!this.$store.state.instance.quotingAvailable) {
|
if (!useInstanceStore().quotingAvailable) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
import useVuelidate from '@vuelidate/core'
|
import useVuelidate from '@vuelidate/core'
|
||||||
import { required, requiredIf, sameAs } from '@vuelidate/validators'
|
import { required, requiredIf, sameAs } from '@vuelidate/validators'
|
||||||
|
import { mapState as mapPiniaState } from 'pinia'
|
||||||
import { mapActions, mapState } from 'vuex'
|
import { mapActions, mapState } from 'vuex'
|
||||||
|
|
||||||
import { DAY } from 'src/services/date_utils/date_utils.js'
|
import { DAY } from 'src/services/date_utils/date_utils.js'
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import localeService from '../../services/locale/locale.service.js'
|
import localeService from '../../services/locale/locale.service.js'
|
||||||
import InterfaceLanguageSwitcher from '../interface_language_switcher/interface_language_switcher.vue'
|
import InterfaceLanguageSwitcher from '../interface_language_switcher/interface_language_switcher.vue'
|
||||||
import TermsOfServicePanel from '../terms_of_service_panel/terms_of_service_panel.vue'
|
import TermsOfServicePanel from '../terms_of_service_panel/terms_of_service_panel.vue'
|
||||||
|
|
@ -96,21 +98,21 @@ const registration = {
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
...mapPiniaState(useInstanceStore, {
|
||||||
|
registrationOpen: (store) => store.registrationOpen,
|
||||||
|
embeddedToS: (store) => store.embeddedToS,
|
||||||
|
termsOfService: (store) => store.tos,
|
||||||
|
accountActivationRequired: (store) => store.accountActivationRequired,
|
||||||
|
accountApprovalRequired: (store) => store.accountApprovalRequired,
|
||||||
|
birthdayRequired: (store) => store.birthdayRequired,
|
||||||
|
birthdayMinAge: (store) => store.birthdayMinAge,
|
||||||
|
}),
|
||||||
...mapState({
|
...mapState({
|
||||||
registrationOpen: (state) => state.instance.registrationOpen,
|
|
||||||
signedIn: (state) => !!state.users.currentUser,
|
signedIn: (state) => !!state.users.currentUser,
|
||||||
isPending: (state) => state.users.signUpPending,
|
isPending: (state) => state.users.signUpPending,
|
||||||
serverValidationErrors: (state) => state.users.signUpErrors,
|
serverValidationErrors: (state) => state.users.signUpErrors,
|
||||||
signUpNotice: (state) => state.users.signUpNotice,
|
signUpNotice: (state) => state.users.signUpNotice,
|
||||||
hasSignUpNotice: (state) => !!state.users.signUpNotice.message,
|
hasSignUpNotice: (state) => !!state.users.signUpNotice.message,
|
||||||
termsOfService: (state) => state.instance.tos,
|
|
||||||
embeddedToS: (state) => state.instance.embeddedToS,
|
|
||||||
accountActivationRequired: (state) =>
|
|
||||||
state.instance.accountActivationRequired,
|
|
||||||
accountApprovalRequired: (state) =>
|
|
||||||
state.instance.accountApprovalRequired,
|
|
||||||
birthdayRequired: (state) => state.instance.birthdayRequired,
|
|
||||||
birthdayMinAge: (state) => state.instance.birthdayMinAge,
|
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import RichContent from 'src/components/rich_content/rich_content.jsx'
|
import RichContent from 'src/components/rich_content/rich_content.jsx'
|
||||||
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
|
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import { useReportsStore } from 'src/stores/reports'
|
import { useReportsStore } from 'src/stores/reports'
|
||||||
import Select from '../select/select.vue'
|
import Select from '../select/select.vue'
|
||||||
import StatusContent from '../status_content/status_content.vue'
|
import StatusContent from '../status_content/status_content.vue'
|
||||||
|
|
@ -31,7 +32,7 @@ const Report = {
|
||||||
return generateProfileLink(
|
return generateProfileLink(
|
||||||
user.id,
|
user.id,
|
||||||
user.screen_name,
|
user.screen_name,
|
||||||
this.$store.state.instance.restrictedNicknames,
|
useInstanceStore().restrictedNicknames,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
setReportState(state) {
|
setReportState(state) {
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import StillImage from 'components/still-image/still-image.vue'
|
||||||
import { assign, clone } from 'lodash'
|
import { assign, clone } from 'lodash'
|
||||||
|
|
||||||
import TabSwitcher from 'src/components/tab_switcher/tab_switcher.jsx'
|
import TabSwitcher from 'src/components/tab_switcher/tab_switcher.jsx'
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import { useInterfaceStore } from 'src/stores/interface'
|
import { useInterfaceStore } from 'src/stores/interface'
|
||||||
import EmojiEditingPopover from '../helpers/emoji_editing_popover.vue'
|
import EmojiEditingPopover from '../helpers/emoji_editing_popover.vue'
|
||||||
import ModifiedIndicator from '../helpers/modified_indicator.vue'
|
import ModifiedIndicator from '../helpers/modified_indicator.vue'
|
||||||
|
|
@ -102,7 +103,7 @@ const EmojiTab = {
|
||||||
// Remote pack
|
// Remote pack
|
||||||
return `${this.pack.remote.instance}/emoji/${encodeURIComponent(this.pack.remote.baseName)}/${name}`
|
return `${this.pack.remote.instance}/emoji/${encodeURIComponent(this.pack.remote.baseName)}/${name}`
|
||||||
} else {
|
} else {
|
||||||
return `${this.$store.state.instance.server}/emoji/${encodeURIComponent(this.packName)}/${name}`
|
return `${useInstanceStore().server}/emoji/${encodeURIComponent(this.packName)}/${name}`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import Attachment from 'src/components/attachment/attachment.vue'
|
import Attachment from 'src/components/attachment/attachment.vue'
|
||||||
import MediaUpload from 'src/components/media_upload/media_upload.vue'
|
import MediaUpload from 'src/components/media_upload/media_upload.vue'
|
||||||
import { fileTypeExt } from 'src/services/file_type/file_type.service.js'
|
import { fileTypeExt } from 'src/services/file_type/file_type.service.js'
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import Setting from './setting.js'
|
import Setting from './setting.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|
@ -24,9 +25,7 @@ export default {
|
||||||
attachment() {
|
attachment() {
|
||||||
const path = this.realDraftMode ? this.draft : this.state
|
const path = this.realDraftMode ? this.draft : this.state
|
||||||
// The "server" part is primarily for local dev, but could be useful for alt-domain or multiuser usage.
|
// The "server" part is primarily for local dev, but could be useful for alt-domain or multiuser usage.
|
||||||
const url = path.includes('://')
|
const url = path.includes('://') ? path : useInstanceStore().server + path
|
||||||
? path
|
|
||||||
: this.$store.state.instance.server + path
|
|
||||||
return {
|
return {
|
||||||
mimetype: fileTypeExt(url),
|
mimetype: fileTypeExt(url),
|
||||||
url,
|
url,
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import Attachment from 'src/components/attachment/attachment.vue'
|
||||||
import MediaUpload from 'src/components/media_upload/media_upload.vue'
|
import MediaUpload from 'src/components/media_upload/media_upload.vue'
|
||||||
import Select from 'src/components/select/select.vue'
|
import Select from 'src/components/select/select.vue'
|
||||||
import { fileTypeExt } from 'src/services/file_type/file_type.service.js'
|
import { fileTypeExt } from 'src/services/file_type/file_type.service.js'
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import Setting from './setting.js'
|
import Setting from './setting.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|
@ -34,9 +35,7 @@ export default {
|
||||||
url: '',
|
url: '',
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const url = path.includes('://')
|
const url = path.includes('://') ? path : useInstanceStore().server + path
|
||||||
? path
|
|
||||||
: this.$store.state.instance.server + path
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
mimetype: fileTypeExt(url),
|
mimetype: fileTypeExt(url),
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import { getCssRules } from 'src/services/theme_data/css_utils.js'
|
||||||
import { deserialize } from 'src/services/theme_data/iss_deserializer.js'
|
import { deserialize } from 'src/services/theme_data/iss_deserializer.js'
|
||||||
import { init } from 'src/services/theme_data/theme_data_3.service.js'
|
import { init } from 'src/services/theme_data/theme_data_3.service.js'
|
||||||
import { convertTheme2To3 } from 'src/services/theme_data/theme2_to_theme3.js'
|
import { convertTheme2To3 } from 'src/services/theme_data/theme2_to_theme3.js'
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import { normalizeThemeData, useInterfaceStore } from 'src/stores/interface'
|
import { normalizeThemeData, useInterfaceStore } from 'src/stores/interface'
|
||||||
import BooleanSetting from '../helpers/boolean_setting.vue'
|
import BooleanSetting from '../helpers/boolean_setting.vue'
|
||||||
import ChoiceSetting from '../helpers/choice_setting.vue'
|
import ChoiceSetting from '../helpers/choice_setting.vue'
|
||||||
|
|
@ -83,7 +84,7 @@ const AppearanceTab = {
|
||||||
|
|
||||||
const updateIndex = (resource) => {
|
const updateIndex = (resource) => {
|
||||||
const capitalizedResource = resource[0].toUpperCase() + resource.slice(1)
|
const capitalizedResource = resource[0].toUpperCase() + resource.slice(1)
|
||||||
const currentIndex = this.$store.state.instance[`${resource}sIndex`]
|
const currentIndex = useInstanceStore()[`${resource}sIndex`]
|
||||||
|
|
||||||
let promise
|
let promise
|
||||||
if (currentIndex) {
|
if (currentIndex) {
|
||||||
|
|
@ -273,11 +274,11 @@ const AppearanceTab = {
|
||||||
return !window.IntersectionObserver
|
return !window.IntersectionObserver
|
||||||
},
|
},
|
||||||
instanceWallpaper() {
|
instanceWallpaper() {
|
||||||
this.$store.state.instance.background
|
useInstanceStore().background
|
||||||
},
|
},
|
||||||
instanceWallpaperUsed() {
|
instanceWallpaperUsed() {
|
||||||
return (
|
return (
|
||||||
this.$store.state.instance.background &&
|
useInstanceStore().background &&
|
||||||
!this.$store.state.users.currentUser.background_image
|
!this.$store.state.users.currentUser.background_image
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
@ -332,20 +333,13 @@ const AppearanceTab = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
isThemeActive(key) {
|
isThemeActive(key) {
|
||||||
return (
|
return key === (this.mergedConfig.theme || useInstanceStore().theme)
|
||||||
key === (this.mergedConfig.theme || this.$store.state.instance.theme)
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
isStyleActive(key) {
|
isStyleActive(key) {
|
||||||
return (
|
return key === (this.mergedConfig.style || useInstanceStore().style)
|
||||||
key === (this.mergedConfig.style || this.$store.state.instance.style)
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
isPaletteActive(key) {
|
isPaletteActive(key) {
|
||||||
return (
|
return key === (this.mergedConfig.palette || useInstanceStore().palette)
|
||||||
key ===
|
|
||||||
(this.mergedConfig.palette || this.$store.state.instance.palette)
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
...mapActions(useInterfaceStore, ['setStyle', 'setTheme']),
|
...mapActions(useInterfaceStore, ['setStyle', 'setTheme']),
|
||||||
setPalette(name, data) {
|
setPalette(name, data) {
|
||||||
|
|
@ -431,10 +425,10 @@ const AppearanceTab = {
|
||||||
if (!file) {
|
if (!file) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (file.size > this.$store.state.instance[slot + 'limit']) {
|
if (file.size > useInstanceStore()[slot + 'limit']) {
|
||||||
const filesize = fileSizeFormatService.fileSizeFormat(file.size)
|
const filesize = fileSizeFormatService.fileSizeFormat(file.size)
|
||||||
const allowedsize = fileSizeFormatService.fileSizeFormat(
|
const allowedsize = fileSizeFormatService.fileSizeFormat(
|
||||||
this.$store.state.instance[slot + 'limit'],
|
useInstanceStore()[slot + 'limit'],
|
||||||
)
|
)
|
||||||
useInterfaceStore().pushGlobalNotice({
|
useInterfaceStore().pushGlobalNotice({
|
||||||
messageKey: 'upload.error.message',
|
messageKey: 'upload.error.message',
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import { mapState as mapVuexState } from 'vuex'
|
||||||
|
|
||||||
import Checkbox from 'src/components/checkbox/checkbox.vue'
|
import Checkbox from 'src/components/checkbox/checkbox.vue'
|
||||||
import Select from 'src/components/select/select.vue'
|
import Select from 'src/components/select/select.vue'
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import { useServerSideStorageStore } from 'src/stores/serverSideStorage'
|
import { useServerSideStorageStore } from 'src/stores/serverSideStorage'
|
||||||
import BooleanSetting from '../helpers/boolean_setting.vue'
|
import BooleanSetting from '../helpers/boolean_setting.vue'
|
||||||
import ChoiceSetting from '../helpers/choice_setting.vue'
|
import ChoiceSetting from '../helpers/choice_setting.vue'
|
||||||
|
|
@ -24,7 +25,7 @@ const ClutterTab = {
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
instanceSpecificPanelPresent() {
|
instanceSpecificPanelPresent() {
|
||||||
return this.$store.state.instance.showInstanceSpecificPanel
|
return useInstanceStore().showInstanceSpecificPanel
|
||||||
},
|
},
|
||||||
...SharedComputedObject(),
|
...SharedComputedObject(),
|
||||||
...mapState(useServerSideStorageStore, {
|
...mapState(useServerSideStorageStore, {
|
||||||
|
|
@ -33,7 +34,7 @@ const ClutterTab = {
|
||||||
muteFiltersObject: (store) => store.prefsStorage.simple.muteFilters,
|
muteFiltersObject: (store) => store.prefsStorage.simple.muteFilters,
|
||||||
}),
|
}),
|
||||||
...mapVuexState({
|
...mapVuexState({
|
||||||
blockExpirationSupported: (state) => state.instance.blockExpiration,
|
blockExpirationSupported: (state) => useInstanceStore().blockExpiration,
|
||||||
}),
|
}),
|
||||||
onMuteDefaultActionLv1: {
|
onMuteDefaultActionLv1: {
|
||||||
get() {
|
get() {
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import ScopeSelector from 'src/components/scope_selector/scope_selector.vue'
|
||||||
import Select from 'src/components/select/select.vue'
|
import Select from 'src/components/select/select.vue'
|
||||||
import localeService from 'src/services/locale/locale.service.js'
|
import localeService from 'src/services/locale/locale.service.js'
|
||||||
import { cacheKey, clearCache, emojiCacheKey } from 'src/services/sw/sw.js'
|
import { cacheKey, clearCache, emojiCacheKey } from 'src/services/sw/sw.js'
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import BooleanSetting from '../helpers/boolean_setting.vue'
|
import BooleanSetting from '../helpers/boolean_setting.vue'
|
||||||
import ChoiceSetting from '../helpers/choice_setting.vue'
|
import ChoiceSetting from '../helpers/choice_setting.vue'
|
||||||
import FloatSetting from '../helpers/float_setting.vue'
|
import FloatSetting from '../helpers/float_setting.vue'
|
||||||
|
|
@ -108,7 +109,7 @@ const ComposingTab = {
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
postFormats() {
|
postFormats() {
|
||||||
return this.$store.state.instance.postFormats || []
|
return useInstanceStore().postFormats || []
|
||||||
},
|
},
|
||||||
postContentOptions() {
|
postContentOptions() {
|
||||||
return this.postFormats.map((format) => ({
|
return this.postFormats.map((format) => ({
|
||||||
|
|
@ -130,7 +131,7 @@ const ComposingTab = {
|
||||||
},
|
},
|
||||||
...SharedComputedObject(),
|
...SharedComputedObject(),
|
||||||
...mapState({
|
...mapState({
|
||||||
blockExpirationSupported: (state) => state.instance.blockExpiration,
|
blockExpirationSupported: (state) => useInstanceStore().blockExpiration,
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import { cacheKey, clearCache, emojiCacheKey } from 'src/services/sw/sw.js'
|
import { cacheKey, clearCache, emojiCacheKey } from 'src/services/sw/sw.js'
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import BooleanSetting from '../helpers/boolean_setting.vue'
|
import BooleanSetting from '../helpers/boolean_setting.vue'
|
||||||
import SharedComputedObject from '../helpers/shared_computed_object.js'
|
import SharedComputedObject from '../helpers/shared_computed_object.js'
|
||||||
|
|
||||||
|
|
@ -7,7 +8,7 @@ const pleromaFeCommitUrl =
|
||||||
|
|
||||||
const VersionTab = {
|
const VersionTab = {
|
||||||
data() {
|
data() {
|
||||||
const instance = this.$store.state.instance
|
const instance = useInstanceStore()
|
||||||
return {
|
return {
|
||||||
backendVersion: instance.backendVersion,
|
backendVersion: instance.backendVersion,
|
||||||
backendRepository: instance.backendRepository,
|
backendRepository: instance.backendRepository,
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import {
|
||||||
newExporter,
|
newExporter,
|
||||||
newImporter,
|
newImporter,
|
||||||
} from 'src/services/export_import/export_import.js'
|
} from 'src/services/export_import/export_import.js'
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import { useInterfaceStore } from 'src/stores/interface'
|
import { useInterfaceStore } from 'src/stores/interface'
|
||||||
import { useServerSideStorageStore } from 'src/stores/serverSideStorage'
|
import { useServerSideStorageStore } from 'src/stores/serverSideStorage'
|
||||||
import BooleanSetting from '../helpers/boolean_setting.vue'
|
import BooleanSetting from '../helpers/boolean_setting.vue'
|
||||||
|
|
@ -90,7 +91,7 @@ const FilteringTab = {
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
instanceSpecificPanelPresent() {
|
instanceSpecificPanelPresent() {
|
||||||
return this.$store.state.instance.showInstanceSpecificPanel
|
return useInstanceStore().showInstanceSpecificPanel
|
||||||
},
|
},
|
||||||
...SharedComputedObject(),
|
...SharedComputedObject(),
|
||||||
...mapState(useServerSideStorageStore, {
|
...mapState(useServerSideStorageStore, {
|
||||||
|
|
@ -99,7 +100,7 @@ const FilteringTab = {
|
||||||
muteFiltersObject: (store) => store.prefsStorage.simple.muteFilters,
|
muteFiltersObject: (store) => store.prefsStorage.simple.muteFilters,
|
||||||
}),
|
}),
|
||||||
...mapVuexState({
|
...mapVuexState({
|
||||||
blockExpirationSupported: (state) => state.instance.blockExpiration,
|
blockExpirationSupported: (state) => useInstanceStore().blockExpiration,
|
||||||
}),
|
}),
|
||||||
onMuteDefaultActionLv1: {
|
onMuteDefaultActionLv1: {
|
||||||
get() {
|
get() {
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import { mapState } from 'vuex'
|
||||||
import FontControl from 'src/components/font_control/font_control.vue'
|
import FontControl from 'src/components/font_control/font_control.vue'
|
||||||
import InterfaceLanguageSwitcher from 'src/components/interface_language_switcher/interface_language_switcher.vue'
|
import InterfaceLanguageSwitcher from 'src/components/interface_language_switcher/interface_language_switcher.vue'
|
||||||
import localeService from 'src/services/locale/locale.service.js'
|
import localeService from 'src/services/locale/locale.service.js'
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import BooleanSetting from '../helpers/boolean_setting.vue'
|
import BooleanSetting from '../helpers/boolean_setting.vue'
|
||||||
import ChoiceSetting from '../helpers/choice_setting.vue'
|
import ChoiceSetting from '../helpers/choice_setting.vue'
|
||||||
import FloatSetting from '../helpers/float_setting.vue'
|
import FloatSetting from '../helpers/float_setting.vue'
|
||||||
|
|
@ -50,7 +51,7 @@ const GeneralTab = {
|
||||||
},
|
},
|
||||||
...SharedComputedObject(),
|
...SharedComputedObject(),
|
||||||
...mapState({
|
...mapState({
|
||||||
blockExpirationSupported: (state) => state.instance.blockExpiration,
|
blockExpirationSupported: (state) => useInstanceStore().blockExpiration,
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import BooleanSetting from '../helpers/boolean_setting.vue'
|
import BooleanSetting from '../helpers/boolean_setting.vue'
|
||||||
import ChoiceSetting from '../helpers/choice_setting.vue'
|
import ChoiceSetting from '../helpers/choice_setting.vue'
|
||||||
import ProfileSettingIndicator from '../helpers/profile_setting_indicator.vue'
|
import ProfileSettingIndicator from '../helpers/profile_setting_indicator.vue'
|
||||||
|
|
@ -30,10 +31,10 @@ const GeneralTab = {
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
postFormats() {
|
postFormats() {
|
||||||
return this.$store.state.instance.postFormats || []
|
return useInstanceStore().postFormats || []
|
||||||
},
|
},
|
||||||
instanceShoutboxPresent() {
|
instanceShoutboxPresent() {
|
||||||
return this.$store.state.instance.shoutAvailable
|
return useInstanceStore().shoutAvailable
|
||||||
},
|
},
|
||||||
columns() {
|
columns() {
|
||||||
const mode = this.$store.getters.mergedConfig.thirdColumnMode
|
const mode = this.$store.getters.mergedConfig.thirdColumnMode
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ import MuteCard from 'src/components/mute_card/mute_card.vue'
|
||||||
import ProgressButton from 'src/components/progress_button/progress_button.vue'
|
import ProgressButton from 'src/components/progress_button/progress_button.vue'
|
||||||
import SelectableList from 'src/components/selectable_list/selectable_list.vue'
|
import SelectableList from 'src/components/selectable_list/selectable_list.vue'
|
||||||
import TabSwitcher from 'src/components/tab_switcher/tab_switcher.jsx'
|
import TabSwitcher from 'src/components/tab_switcher/tab_switcher.jsx'
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import { useOAuthTokensStore } from 'src/stores/oauth_tokens'
|
import { useOAuthTokensStore } from 'src/stores/oauth_tokens'
|
||||||
|
|
||||||
const BlockList = withLoadMore({
|
const BlockList = withLoadMore({
|
||||||
|
|
@ -64,7 +65,7 @@ const MutesAndBlocks = {
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
knownDomains() {
|
knownDomains() {
|
||||||
return this.$store.state.instance.knownDomains
|
return useInstanceStore().knownDomains
|
||||||
},
|
},
|
||||||
user() {
|
user() {
|
||||||
return this.$store.state.users.currentUser
|
return this.$store.state.users.currentUser
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,7 @@ import {
|
||||||
} from 'src/services/theme_data/theme_data.service.js'
|
} from 'src/services/theme_data/theme_data.service.js'
|
||||||
import { init } from 'src/services/theme_data/theme_data_3.service.js'
|
import { init } from 'src/services/theme_data/theme_data_3.service.js'
|
||||||
import { convertTheme2To3 } from 'src/services/theme_data/theme2_to_theme3.js'
|
import { convertTheme2To3 } from 'src/services/theme_data/theme2_to_theme3.js'
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import { useInterfaceStore } from 'src/stores/interface'
|
import { useInterfaceStore } from 'src/stores/interface'
|
||||||
import Preview from './theme_preview.vue'
|
import Preview from './theme_preview.vue'
|
||||||
|
|
||||||
|
|
@ -125,7 +126,7 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
const currentIndex = this.$store.state.instance.themesIndex
|
const currentIndex = useInstanceStore().themesIndex
|
||||||
|
|
||||||
let promise
|
let promise
|
||||||
if (currentIndex) {
|
if (currentIndex) {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import Checkbox from 'src/components/checkbox/checkbox.vue'
|
import Checkbox from 'src/components/checkbox/checkbox.vue'
|
||||||
import ProgressButton from 'src/components/progress_button/progress_button.vue'
|
import ProgressButton from 'src/components/progress_button/progress_button.vue'
|
||||||
import localeService from 'src/services/locale/locale.service.js'
|
import localeService from 'src/services/locale/locale.service.js'
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import { useOAuthTokensStore } from 'src/stores/oauth_tokens'
|
import { useOAuthTokensStore } from 'src/stores/oauth_tokens'
|
||||||
import Mfa from './mfa.vue'
|
import Mfa from './mfa.vue'
|
||||||
|
|
||||||
|
|
@ -42,7 +43,7 @@ const SecurityTab = {
|
||||||
return this.$store.state.users.currentUser
|
return this.$store.state.users.currentUser
|
||||||
},
|
},
|
||||||
pleromaExtensionsAvailable() {
|
pleromaExtensionsAvailable() {
|
||||||
return this.$store.state.instance.pleromaExtensionsAvailable
|
return useInstanceStore().pleromaExtensionsAvailable
|
||||||
},
|
},
|
||||||
oauthTokens() {
|
oauthTokens() {
|
||||||
return useOAuthTokensStore().tokens.map((oauthToken) => {
|
return useOAuthTokensStore().tokens.map((oauthToken) => {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
|
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import { useShoutStore } from 'src/stores/shout'
|
import { useShoutStore } from 'src/stores/shout'
|
||||||
|
|
||||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||||
|
|
@ -32,7 +33,7 @@ const shoutPanel = {
|
||||||
return generateProfileLink(
|
return generateProfileLink(
|
||||||
user.id,
|
user.id,
|
||||||
user.username,
|
user.username,
|
||||||
this.$store.state.instance.restrictedNicknames,
|
useInstanceStore().restrictedNicknames,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import { mapGetters, mapState } from 'vuex'
|
||||||
|
|
||||||
import { USERNAME_ROUTES } from 'src/components/navigation/navigation.js'
|
import { USERNAME_ROUTES } from 'src/components/navigation/navigation.js'
|
||||||
import { useAnnouncementsStore } from 'src/stores/announcements'
|
import { useAnnouncementsStore } from 'src/stores/announcements'
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import { useInterfaceStore } from 'src/stores/interface'
|
import { useInterfaceStore } from 'src/stores/interface'
|
||||||
import { useShoutStore } from 'src/stores/shout'
|
import { useShoutStore } from 'src/stores/shout'
|
||||||
import GestureService from '../../services/gesture_service/gesture_service'
|
import GestureService from '../../services/gesture_service/gesture_service'
|
||||||
|
|
@ -75,25 +76,25 @@ const SideDrawer = {
|
||||||
return this.unseenNotifications.length
|
return this.unseenNotifications.length
|
||||||
},
|
},
|
||||||
suggestionsEnabled() {
|
suggestionsEnabled() {
|
||||||
return this.$store.state.instance.suggestionsEnabled
|
return useInstanceStore().suggestionsEnabled
|
||||||
},
|
},
|
||||||
logo() {
|
logo() {
|
||||||
return this.$store.state.instance.logo
|
return useInstanceStore().logo
|
||||||
},
|
},
|
||||||
hideSitename() {
|
hideSitename() {
|
||||||
return this.$store.state.instance.hideSitename
|
return useInstanceStore().hideSitename
|
||||||
},
|
},
|
||||||
sitename() {
|
sitename() {
|
||||||
return this.$store.state.instance.name
|
return useInstanceStore().name
|
||||||
},
|
},
|
||||||
followRequestCount() {
|
followRequestCount() {
|
||||||
return this.$store.state.api.followRequests.length
|
return this.$store.state.api.followRequests.length
|
||||||
},
|
},
|
||||||
privateMode() {
|
privateMode() {
|
||||||
return this.$store.state.instance.private
|
return useInstanceStore().private
|
||||||
},
|
},
|
||||||
federating() {
|
federating() {
|
||||||
return this.$store.state.instance.federating
|
return useInstanceStore().federating
|
||||||
},
|
},
|
||||||
timelinesRoute() {
|
timelinesRoute() {
|
||||||
let name
|
let name
|
||||||
|
|
@ -113,7 +114,7 @@ const SideDrawer = {
|
||||||
}),
|
}),
|
||||||
...mapState({
|
...mapState({
|
||||||
pleromaChatMessagesAvailable: (state) =>
|
pleromaChatMessagesAvailable: (state) =>
|
||||||
state.instance.pleromaChatMessagesAvailable,
|
useInstanceStore().pleromaChatMessagesAvailable,
|
||||||
}),
|
}),
|
||||||
...mapGetters(['unreadChatCount', 'draftCount']),
|
...mapGetters(['unreadChatCount', 'draftCount']),
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,12 @@ import groupBy from 'lodash/groupBy'
|
||||||
import map from 'lodash/map'
|
import map from 'lodash/map'
|
||||||
import { mapGetters, mapState } from 'vuex'
|
import { mapGetters, mapState } from 'vuex'
|
||||||
|
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import BasicUserCard from '../basic_user_card/basic_user_card.vue'
|
import BasicUserCard from '../basic_user_card/basic_user_card.vue'
|
||||||
|
|
||||||
const StaffPanel = {
|
const StaffPanel = {
|
||||||
created() {
|
created() {
|
||||||
const nicknames = this.$store.state.instance.staffAccounts
|
const nicknames = useInstanceStore().staffAccounts
|
||||||
nicknames.forEach((nickname) =>
|
nicknames.forEach((nickname) =>
|
||||||
this.$store.dispatch('fetchUserIfMissing', nickname),
|
this.$store.dispatch('fetchUserIfMissing', nickname),
|
||||||
)
|
)
|
||||||
|
|
@ -28,7 +29,7 @@ const StaffPanel = {
|
||||||
},
|
},
|
||||||
...mapGetters(['findUserByName']),
|
...mapGetters(['findUserByName']),
|
||||||
...mapState({
|
...mapState({
|
||||||
staffAccounts: (state) => state.instance.staffAccounts,
|
staffAccounts: (state) => useInstanceStore().staffAccounts,
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import MentionsLine from 'src/components/mentions_line/mentions_line.vue'
|
||||||
import RichContent from 'src/components/rich_content/rich_content.jsx'
|
import RichContent from 'src/components/rich_content/rich_content.jsx'
|
||||||
import StatusActionButtons from 'src/components/status_action_buttons/status_action_buttons.vue'
|
import StatusActionButtons from 'src/components/status_action_buttons/status_action_buttons.vue'
|
||||||
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
|
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import { useServerSideStorageStore } from 'src/stores/serverSideStorage'
|
import { useServerSideStorageStore } from 'src/stores/serverSideStorage'
|
||||||
import { muteFilterHits } from '../../services/status_parser/status_parser.js'
|
import { muteFilterHits } from '../../services/status_parser/status_parser.js'
|
||||||
import {
|
import {
|
||||||
|
|
@ -494,7 +495,7 @@ const Status = {
|
||||||
return this.status.edited_at !== null
|
return this.status.edited_at !== null
|
||||||
},
|
},
|
||||||
editingAvailable() {
|
editingAvailable() {
|
||||||
return this.$store.state.instance.editingAvailable
|
return useInstanceStore().editingAvailable
|
||||||
},
|
},
|
||||||
hasVisibleQuote() {
|
hasVisibleQuote() {
|
||||||
return this.status.quote_url && this.status.quote_visible
|
return this.status.quote_url && this.status.quote_visible
|
||||||
|
|
@ -588,7 +589,7 @@ const Status = {
|
||||||
return generateProfileLink(
|
return generateProfileLink(
|
||||||
id,
|
id,
|
||||||
name,
|
name,
|
||||||
this.$store.state.instance.restrictedNicknames,
|
useInstanceStore().restrictedNicknames,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
addMediaPlaying(id) {
|
addMediaPlaying(id) {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import EmojiPicker from 'src/components/emoji_picker/emoji_picker.vue'
|
import EmojiPicker from 'src/components/emoji_picker/emoji_picker.vue'
|
||||||
import Popover from 'src/components/popover/popover.vue'
|
import Popover from 'src/components/popover/popover.vue'
|
||||||
import StatusBookmarkFolderMenu from 'src/components/status_bookmark_folder_menu/status_bookmark_folder_menu.vue'
|
import StatusBookmarkFolderMenu from 'src/components/status_bookmark_folder_menu/status_bookmark_folder_menu.vue'
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
|
|
||||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||||
import {
|
import {
|
||||||
|
|
@ -91,7 +92,7 @@ export default {
|
||||||
return this.status.thread_muted
|
return this.status.thread_muted
|
||||||
},
|
},
|
||||||
hideCustomEmoji() {
|
hideCustomEmoji() {
|
||||||
return !this.$store.state.instance.pleromaCustomEmojiReactionsAvailable
|
return !useInstanceStore().pleromaCustomEmojiReactionsAvailable
|
||||||
},
|
},
|
||||||
buttonInnerClass() {
|
buttonInnerClass() {
|
||||||
return [
|
return [
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import { useEditStatusStore } from 'src/stores/editStatus.js'
|
import { useEditStatusStore } from 'src/stores/editStatus.js'
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import { useReportsStore } from 'src/stores/reports.js'
|
import { useReportsStore } from 'src/stores/reports.js'
|
||||||
import { useStatusHistoryStore } from 'src/stores/statusHistory.js'
|
import { useStatusHistoryStore } from 'src/stores/statusHistory.js'
|
||||||
|
|
||||||
|
|
@ -159,7 +160,7 @@ export const BUTTONS = [
|
||||||
icon: 'history',
|
icon: 'history',
|
||||||
label: 'status.status_history',
|
label: 'status.status_history',
|
||||||
if({ status, state }) {
|
if({ status, state }) {
|
||||||
return state.instance.editingAvailable && status.edited_at !== null
|
return useInstanceStore().editingAvailable && status.edited_at !== null
|
||||||
},
|
},
|
||||||
action({ status }) {
|
action({ status }) {
|
||||||
const originalStatus = { ...status }
|
const originalStatus = { ...status }
|
||||||
|
|
@ -189,7 +190,7 @@ export const BUTTONS = [
|
||||||
if({ status, loggedIn, currentUser, state }) {
|
if({ status, loggedIn, currentUser, state }) {
|
||||||
return (
|
return (
|
||||||
loggedIn &&
|
loggedIn &&
|
||||||
state.instance.editingAvailable &&
|
useInstanceStore().editingAvailable &&
|
||||||
status.user.id === currentUser.id
|
status.user.id === currentUser.id
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
@ -243,7 +244,7 @@ export const BUTTONS = [
|
||||||
action({ state, status, router }) {
|
action({ state, status, router }) {
|
||||||
navigator.clipboard.writeText(
|
navigator.clipboard.writeText(
|
||||||
[
|
[
|
||||||
state.instance.server,
|
useInstanceStore().server,
|
||||||
router.resolve({ name: 'conversation', params: { id: status.id } })
|
router.resolve({ name: 'conversation', params: { id: status.id } })
|
||||||
.href,
|
.href,
|
||||||
].join(''),
|
].join(''),
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
/* eslint-env browser */
|
/* eslint-env browser */
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import statusPosterService from '../../services/status_poster/status_poster.service.js'
|
import statusPosterService from '../../services/status_poster/status_poster.service.js'
|
||||||
import TabSwitcher from '../tab_switcher/tab_switcher.jsx'
|
import TabSwitcher from '../tab_switcher/tab_switcher.jsx'
|
||||||
|
|
||||||
|
|
@ -16,7 +17,7 @@ const StickerPicker = {
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
pack() {
|
pack() {
|
||||||
return this.$store.state.instance.stickers || []
|
return useInstanceStore().stickers || []
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,7 @@ import Popover from 'components/popover/popover.vue'
|
||||||
import SelectComponent from 'components/select/select.vue'
|
import SelectComponent from 'components/select/select.vue'
|
||||||
import { assign } from 'lodash'
|
import { assign } from 'lodash'
|
||||||
|
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import { useInterfaceStore } from 'src/stores/interface'
|
import { useInterfaceStore } from 'src/stores/interface'
|
||||||
import StillImage from './still-image.vue'
|
import StillImage from './still-image.vue'
|
||||||
|
|
||||||
|
|
@ -125,7 +126,7 @@ export default {
|
||||||
const allPacks = {}
|
const allPacks = {}
|
||||||
|
|
||||||
return listFunction({
|
return listFunction({
|
||||||
instance: this.$store.state.instance.server,
|
instance: useInstanceStore().server,
|
||||||
page: 1,
|
page: 1,
|
||||||
pageSize: 0,
|
pageSize: 0,
|
||||||
})
|
})
|
||||||
|
|
@ -140,7 +141,7 @@ export default {
|
||||||
resultingPromise = resultingPromise
|
resultingPromise = resultingPromise
|
||||||
.then(() =>
|
.then(() =>
|
||||||
listFunction({
|
listFunction({
|
||||||
instance: this.$store.state.instance.server,
|
instance: useInstanceStore().server,
|
||||||
page: i,
|
page: i,
|
||||||
pageSize,
|
pageSize,
|
||||||
}),
|
}),
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
|
|
||||||
const TermsOfServicePanel = {
|
const TermsOfServicePanel = {
|
||||||
computed: {
|
computed: {
|
||||||
content() {
|
content() {
|
||||||
return this.$store.state.instance.tos
|
return useInstanceStore().tos
|
||||||
},
|
},
|
||||||
embedded() {
|
embedded() {
|
||||||
return this.$store.state.instance.embeddedToS
|
return useInstanceStore().embeddedToS
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import { filterNavigation } from 'src/components/navigation/filter.js'
|
||||||
import { TIMELINES } from 'src/components/navigation/navigation.js'
|
import { TIMELINES } from 'src/components/navigation/navigation.js'
|
||||||
import NavigationEntry from 'src/components/navigation/navigation_entry.vue'
|
import NavigationEntry from 'src/components/navigation/navigation_entry.vue'
|
||||||
import { useBookmarkFoldersStore } from 'src/stores/bookmark_folders'
|
import { useBookmarkFoldersStore } from 'src/stores/bookmark_folders'
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import { useInterfaceStore } from 'src/stores/interface'
|
import { useInterfaceStore } from 'src/stores/interface'
|
||||||
import { useListsStore } from 'src/stores/lists'
|
import { useListsStore } from 'src/stores/lists'
|
||||||
import BookmarkFoldersMenuContent from '../bookmark_folders_menu/bookmark_folders_menu_content.vue'
|
import BookmarkFoldersMenuContent from '../bookmark_folders_menu/bookmark_folders_menu_content.vue'
|
||||||
|
|
@ -60,11 +61,12 @@ const TimelineMenu = {
|
||||||
},
|
},
|
||||||
...mapState({
|
...mapState({
|
||||||
currentUser: (state) => state.users.currentUser,
|
currentUser: (state) => state.users.currentUser,
|
||||||
privateMode: (state) => state.instance.private,
|
privateMode: (state) => useInstanceStore().private,
|
||||||
federating: (state) => state.instance.federating,
|
federating: (state) => useInstanceStore().federating,
|
||||||
bookmarkFolders: (state) =>
|
bookmarkFolders: (state) =>
|
||||||
state.instance.pleromaBookmarkFoldersAvailable,
|
useInstanceStore().pleromaBookmarkFoldersAvailable,
|
||||||
bubbleTimeline: (state) => state.instance.localBubbleInstances.length > 0,
|
bubbleTimeline: (state) =>
|
||||||
|
useInstanceStore().localBubbleInstances.length > 0,
|
||||||
}),
|
}),
|
||||||
timelinesList() {
|
timelinesList() {
|
||||||
return filterNavigation(
|
return filterNavigation(
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import pleromaTanFoxMask from 'src/assets/pleromatan_apology_fox_mask.png'
|
import pleromaTanFoxMask from 'src/assets/pleromatan_apology_fox_mask.png'
|
||||||
import pleromaTanMask from 'src/assets/pleromatan_apology_mask.png'
|
import pleromaTanMask from 'src/assets/pleromatan_apology_mask.png'
|
||||||
import Modal from 'src/components/modal/modal.vue'
|
import Modal from 'src/components/modal/modal.vue'
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import { useServerSideStorageStore } from 'src/stores/serverSideStorage'
|
import { useServerSideStorageStore } from 'src/stores/serverSideStorage'
|
||||||
|
|
||||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||||
|
|
@ -36,7 +37,7 @@ const UpdateNotification = {
|
||||||
},
|
},
|
||||||
shouldShow() {
|
shouldShow() {
|
||||||
return (
|
return (
|
||||||
!this.$store.state.instance.disableUpdateNotification &&
|
!useInstanceStore().disableUpdateNotification &&
|
||||||
this.$store.state.users.currentUser &&
|
this.$store.state.users.currentUser &&
|
||||||
useServerSideStorageStore().flagStorage.updateCounter <
|
useServerSideStorageStore().flagStorage.updateCounter <
|
||||||
CURRENT_UPDATE_COUNTER &&
|
CURRENT_UPDATE_COUNTER &&
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import { useInterfaceStore } from 'src/stores/interface'
|
import { useInterfaceStore } from 'src/stores/interface'
|
||||||
import StillImage from '../still-image/still-image.vue'
|
import StillImage from '../still-image/still-image.vue'
|
||||||
|
|
||||||
|
|
@ -35,7 +36,7 @@ const UserAvatar = {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
showPlaceholder: false,
|
showPlaceholder: false,
|
||||||
defaultAvatar: `${this.$store.state.instance.server + this.$store.state.instance.defaultAvatar}`,
|
defaultAvatar: `${useInstanceStore().server + useInstanceStore().defaultAvatar}`,
|
||||||
betterShadow: useInterfaceStore().browserSupport.cssFilter,
|
betterShadow: useInterfaceStore().browserSupport.cssFilter,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ import UserTimedFilterModal from 'src/components/user_timed_filter_modal/user_ti
|
||||||
import { propsToNative } from 'src/services/attributes_helper/attributes_helper.service.js'
|
import { propsToNative } from 'src/services/attributes_helper/attributes_helper.service.js'
|
||||||
import localeService from 'src/services/locale/locale.service.js'
|
import localeService from 'src/services/locale/locale.service.js'
|
||||||
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
|
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import { usePostStatusStore } from 'src/stores/post_status'
|
import { usePostStatusStore } from 'src/stores/post_status'
|
||||||
import { useInterfaceStore } from '../../stores/interface'
|
import { useInterfaceStore } from '../../stores/interface'
|
||||||
import { useMediaViewerStore } from '../../stores/media_viewer'
|
import { useMediaViewerStore } from '../../stores/media_viewer'
|
||||||
|
|
@ -176,7 +177,7 @@ export default {
|
||||||
return false
|
return false
|
||||||
},
|
},
|
||||||
groupActorAvailable() {
|
groupActorAvailable() {
|
||||||
return this.$store.state.instance.groupActorAvailable
|
return useInstanceStore().groupActorAvailable
|
||||||
},
|
},
|
||||||
availableActorTypes() {
|
availableActorTypes() {
|
||||||
return this.groupActorAvailable
|
return this.groupActorAvailable
|
||||||
|
|
@ -209,7 +210,7 @@ export default {
|
||||||
return Math.round(this.user.statuses_count / days)
|
return Math.round(this.user.statuses_count / days)
|
||||||
},
|
},
|
||||||
emoji() {
|
emoji() {
|
||||||
return this.$store.state.instance.customEmoji.map((e) => ({
|
return useInstanceStore().customEmoji.map((e) => ({
|
||||||
shortcode: e.displayText,
|
shortcode: e.displayText,
|
||||||
static_url: e.imageUrl,
|
static_url: e.imageUrl,
|
||||||
url: e.imageUrl,
|
url: e.imageUrl,
|
||||||
|
|
@ -335,19 +336,13 @@ export default {
|
||||||
return this.newBanner === null ? currentUrl : newUrl
|
return this.newBanner === null ? currentUrl : newUrl
|
||||||
},
|
},
|
||||||
defaultAvatar() {
|
defaultAvatar() {
|
||||||
return (
|
return useInstanceStore().server + useInstanceStore().defaultAvatar
|
||||||
this.$store.state.instance.server +
|
|
||||||
this.$store.state.instance.defaultAvatar
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
defaultBanner() {
|
defaultBanner() {
|
||||||
return (
|
return useInstanceStore().server + useInstanceStore().defaultBanner
|
||||||
this.$store.state.instance.server +
|
|
||||||
this.$store.state.instance.defaultBanner
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
isDefaultAvatar() {
|
isDefaultAvatar() {
|
||||||
const baseAvatar = this.$store.state.instance.defaultAvatar
|
const baseAvatar = useInstanceStore().defaultAvatar
|
||||||
return (
|
return (
|
||||||
!this.$store.state.users.currentUser.profile_image_url ||
|
!this.$store.state.users.currentUser.profile_image_url ||
|
||||||
this.$store.state.users.currentUser.profile_image_url.includes(
|
this.$store.state.users.currentUser.profile_image_url.includes(
|
||||||
|
|
@ -356,14 +351,14 @@ export default {
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
isDefaultBanner() {
|
isDefaultBanner() {
|
||||||
const baseBanner = this.$store.state.instance.defaultBanner
|
const baseBanner = useInstanceStore().defaultBanner
|
||||||
return (
|
return (
|
||||||
!this.$store.state.users.currentUser.cover_photo ||
|
!this.$store.state.users.currentUser.cover_photo ||
|
||||||
this.$store.state.users.currentUser.cover_photo.includes(baseBanner)
|
this.$store.state.users.currentUser.cover_photo.includes(baseBanner)
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
fieldsLimits() {
|
fieldsLimits() {
|
||||||
return this.$store.state.instance.fieldsLimits
|
return useInstanceStore().fieldsLimits
|
||||||
},
|
},
|
||||||
maxFields() {
|
maxFields() {
|
||||||
return this.fieldsLimits ? this.fieldsLimits.maxFields : 0
|
return this.fieldsLimits ? this.fieldsLimits.maxFields : 0
|
||||||
|
|
@ -372,7 +367,7 @@ export default {
|
||||||
return suggestor({
|
return suggestor({
|
||||||
emoji: [
|
emoji: [
|
||||||
...this.$store.getters.standardEmojiList,
|
...this.$store.getters.standardEmojiList,
|
||||||
...this.$store.state.instance.customEmoji,
|
...useInstanceStore().customEmoji,
|
||||||
],
|
],
|
||||||
store: this.$store,
|
store: this.$store,
|
||||||
})
|
})
|
||||||
|
|
@ -381,7 +376,7 @@ export default {
|
||||||
return suggestor({
|
return suggestor({
|
||||||
emoji: [
|
emoji: [
|
||||||
...this.$store.getters.standardEmojiList,
|
...this.$store.getters.standardEmojiList,
|
||||||
...this.$store.state.instance.customEmoji,
|
...useInstanceStore().customEmoji,
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
@ -412,7 +407,7 @@ export default {
|
||||||
return generateProfileLink(
|
return generateProfileLink(
|
||||||
user.id,
|
user.id,
|
||||||
user.screen_name,
|
user.screen_name,
|
||||||
this.$store.state.instance.restrictedNicknames,
|
useInstanceStore().restrictedNicknames,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
openProfileTab() {
|
openProfileTab() {
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
|
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import UnicodeDomainIndicator from '../unicode_domain_indicator/unicode_domain_indicator.vue'
|
import UnicodeDomainIndicator from '../unicode_domain_indicator/unicode_domain_indicator.vue'
|
||||||
|
|
||||||
const UserLink = {
|
const UserLink = {
|
||||||
|
|
@ -33,7 +34,7 @@ const UserLink = {
|
||||||
return generateProfileLink(
|
return generateProfileLink(
|
||||||
user.id,
|
user.id,
|
||||||
user.screen_name,
|
user.screen_name,
|
||||||
this.$store.state.instance.restrictedNicknames,
|
useInstanceStore().restrictedNicknames,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import get from 'lodash/get'
|
||||||
|
|
||||||
import RichContent from 'src/components/rich_content/rich_content.jsx'
|
import RichContent from 'src/components/rich_content/rich_content.jsx'
|
||||||
import TabSwitcher from 'src/components/tab_switcher/tab_switcher.jsx'
|
import TabSwitcher from 'src/components/tab_switcher/tab_switcher.jsx'
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import withLoadMore from '../../hocs/with_load_more/with_load_more'
|
import withLoadMore from '../../hocs/with_load_more/with_load_more'
|
||||||
import Conversation from '../conversation/conversation.vue'
|
import Conversation from '../conversation/conversation.vue'
|
||||||
import FollowCard from '../follow_card/follow_card.vue'
|
import FollowCard from '../follow_card/follow_card.vue'
|
||||||
|
|
@ -87,7 +88,7 @@ const UserProfile = {
|
||||||
favoritesTabVisible() {
|
favoritesTabVisible() {
|
||||||
return (
|
return (
|
||||||
this.isUs ||
|
this.isUs ||
|
||||||
(this.$store.state.instance.pleromaPublicFavouritesAvailable &&
|
(useInstanceStore().pleromaPublicFavouritesAvailable &&
|
||||||
!this.user.hide_favorites)
|
!this.user.hide_favorites)
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import { shuffle } from 'lodash'
|
import { shuffle } from 'lodash'
|
||||||
|
|
||||||
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
|
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import apiService from '../../services/api/api.service.js'
|
import apiService from '../../services/api/api.service.js'
|
||||||
|
|
||||||
function showWhoToFollow(panel, reply) {
|
function showWhoToFollow(panel, reply) {
|
||||||
|
|
@ -8,7 +9,7 @@ function showWhoToFollow(panel, reply) {
|
||||||
|
|
||||||
panel.usersToFollow.forEach((toFollow, index) => {
|
panel.usersToFollow.forEach((toFollow, index) => {
|
||||||
const user = shuffled[index]
|
const user = shuffled[index]
|
||||||
const img = user.avatar || this.$store.state.instance.defaultAvatar
|
const img = user.avatar || useInstanceStore().defaultAvatar
|
||||||
const name = user.acct
|
const name = user.acct
|
||||||
|
|
||||||
toFollow.img = img
|
toFollow.img = img
|
||||||
|
|
@ -46,7 +47,7 @@ const WhoToFollowPanel = {
|
||||||
return this.$store.state.users.currentUser.screen_name
|
return this.$store.state.users.currentUser.screen_name
|
||||||
},
|
},
|
||||||
suggestionsEnabled() {
|
suggestionsEnabled() {
|
||||||
return this.$store.state.instance.suggestionsEnabled
|
return useInstanceStore().suggestionsEnabled
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
@ -54,7 +55,7 @@ const WhoToFollowPanel = {
|
||||||
return generateProfileLink(
|
return generateProfileLink(
|
||||||
id,
|
id,
|
||||||
name,
|
name,
|
||||||
this.$store.state.instance.restrictedNicknames,
|
useInstanceStore().restrictedNicknames,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -67,7 +68,7 @@ const WhoToFollowPanel = {
|
||||||
},
|
},
|
||||||
mounted: function () {
|
mounted: function () {
|
||||||
this.usersToFollow = new Array(3).fill().map(() => ({
|
this.usersToFollow = new Array(3).fill().map(() => ({
|
||||||
img: this.$store.state.instance.defaultAvatar,
|
img: useInstanceStore().defaultAvatar,
|
||||||
name: '',
|
name: '',
|
||||||
id: 0,
|
id: 0,
|
||||||
}))
|
}))
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import { useInterfaceStore } from 'src/stores/interface'
|
import { useInterfaceStore } from 'src/stores/interface'
|
||||||
|
|
||||||
export default (store) => {
|
export default (store) => {
|
||||||
store.subscribe((mutation, state) => {
|
store.subscribe((mutation, state) => {
|
||||||
const vapidPublicKey = state.instance.vapidPublicKey
|
const vapidPublicKey = useInstanceStore().vapidPublicKey
|
||||||
const webPushNotification = state.config.webPushNotifications
|
const webPushNotification = state.config.webPushNotifications
|
||||||
const permission = useInterfaceStore().notificationPermission === 'granted'
|
const permission = useInterfaceStore().notificationPermission === 'granted'
|
||||||
const user = state.users.currentUser
|
const user = state.users.currentUser
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import { Socket } from 'phoenix'
|
import { Socket } from 'phoenix'
|
||||||
|
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import { useInterfaceStore } from 'src/stores/interface.js'
|
import { useInterfaceStore } from 'src/stores/interface.js'
|
||||||
import { useShoutStore } from 'src/stores/shout.js'
|
import { useShoutStore } from 'src/stores/shout.js'
|
||||||
import { WSConnectionStatus } from '../services/api/api.service.js'
|
import { WSConnectionStatus } from '../services/api/api.service.js'
|
||||||
|
|
@ -237,7 +238,7 @@ const api = {
|
||||||
) {
|
) {
|
||||||
if (
|
if (
|
||||||
timeline === 'favourites' &&
|
timeline === 'favourites' &&
|
||||||
!store.rootState.instance.pleromaPublicFavouritesAvailable
|
!useInstanceStore().pleromaPublicFavouritesAvailable
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
if (store.state.fetchers[timeline]) return
|
if (store.state.fetchers[timeline]) return
|
||||||
|
|
@ -322,7 +323,7 @@ const api = {
|
||||||
// Bookmark folders
|
// Bookmark folders
|
||||||
startFetchingBookmarkFolders(store) {
|
startFetchingBookmarkFolders(store) {
|
||||||
if (store.state.fetchers.bookmarkFolders) return
|
if (store.state.fetchers.bookmarkFolders) return
|
||||||
if (!store.rootState.instance.pleromaBookmarkFoldersAvailable) return
|
if (!useInstanceStore().pleromaBookmarkFoldersAvailable) return
|
||||||
const fetcher =
|
const fetcher =
|
||||||
store.state.backendInteractor.startFetchingBookmarkFolders({ store })
|
store.state.backendInteractor.startFetchingBookmarkFolders({ store })
|
||||||
store.commit('addFetcher', { fetcherName: 'bookmarkFolders', fetcher })
|
store.commit('addFetcher', { fetcherName: 'bookmarkFolders', fetcher })
|
||||||
|
|
@ -341,7 +342,7 @@ const api = {
|
||||||
// Set up websocket connection
|
// Set up websocket connection
|
||||||
const token = state.wsToken
|
const token = state.wsToken
|
||||||
if (
|
if (
|
||||||
rootState.instance.shoutAvailable &&
|
useInstanceStore().shoutAvailable &&
|
||||||
typeof token !== 'undefined' &&
|
typeof token !== 'undefined' &&
|
||||||
state.socket === null
|
state.socket === null
|
||||||
) {
|
) {
|
||||||
|
|
|
||||||
|
|
@ -1,376 +0,0 @@
|
||||||
// See build/emojis_plugin for more details
|
|
||||||
|
|
||||||
import { useInterfaceStore } from 'src/stores/interface.js'
|
|
||||||
import { ensureFinalFallback } from '../i18n/languages.js'
|
|
||||||
import apiService from '../services/api/api.service.js'
|
|
||||||
import { instanceDefaultProperties } from './config.js'
|
|
||||||
import {
|
|
||||||
instanceDefaultConfig,
|
|
||||||
staticOrApiConfigDefault,
|
|
||||||
} from './default_config_state.js'
|
|
||||||
|
|
||||||
import { annotationsLoader } from 'virtual:pleroma-fe/emoji-annotations'
|
|
||||||
|
|
||||||
const SORTED_EMOJI_GROUP_IDS = [
|
|
||||||
'smileys-and-emotion',
|
|
||||||
'people-and-body',
|
|
||||||
'animals-and-nature',
|
|
||||||
'food-and-drink',
|
|
||||||
'travel-and-places',
|
|
||||||
'activities',
|
|
||||||
'objects',
|
|
||||||
'symbols',
|
|
||||||
'flags',
|
|
||||||
]
|
|
||||||
|
|
||||||
const REGIONAL_INDICATORS = (() => {
|
|
||||||
const start = 0x1f1e6
|
|
||||||
const end = 0x1f1ff
|
|
||||||
const A = 'A'.codePointAt(0)
|
|
||||||
const res = new Array(end - start + 1)
|
|
||||||
for (let i = start; i <= end; ++i) {
|
|
||||||
const letter = String.fromCodePoint(A + i - start)
|
|
||||||
res[i - start] = {
|
|
||||||
replacement: String.fromCodePoint(i),
|
|
||||||
imageUrl: false,
|
|
||||||
displayText: 'regional_indicator_' + letter,
|
|
||||||
displayTextI18n: {
|
|
||||||
key: 'emoji.regional_indicator',
|
|
||||||
args: { letter },
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res
|
|
||||||
})()
|
|
||||||
|
|
||||||
const REMOTE_INTERACTION_URL = '/main/ostatus'
|
|
||||||
|
|
||||||
const defaultState = {
|
|
||||||
// Stuff from apiConfig
|
|
||||||
name: 'Pleroma FE',
|
|
||||||
registrationOpen: true,
|
|
||||||
server: 'http://localhost:4040/',
|
|
||||||
textlimit: 5000,
|
|
||||||
themesIndex: undefined,
|
|
||||||
stylesIndex: undefined,
|
|
||||||
palettesIndex: undefined,
|
|
||||||
themeData: undefined, // used for theme editor v2
|
|
||||||
vapidPublicKey: undefined,
|
|
||||||
|
|
||||||
// Stuff from static/config.json
|
|
||||||
loginMethod: 'password',
|
|
||||||
disableUpdateNotification: false,
|
|
||||||
|
|
||||||
fontsOverride: {},
|
|
||||||
|
|
||||||
// Instance-wide configurations that should not be changed by individual users
|
|
||||||
...staticOrApiConfigDefault,
|
|
||||||
// Instance admins can override default settings for the whole instance
|
|
||||||
...instanceDefaultConfig,
|
|
||||||
|
|
||||||
// Nasty stuff
|
|
||||||
customEmoji: [],
|
|
||||||
customEmojiFetched: false,
|
|
||||||
emoji: {},
|
|
||||||
emojiFetched: false,
|
|
||||||
unicodeEmojiAnnotations: {},
|
|
||||||
pleromaExtensionsAvailable: true,
|
|
||||||
postFormats: [],
|
|
||||||
restrictedNicknames: [],
|
|
||||||
safeDM: true,
|
|
||||||
knownDomains: [],
|
|
||||||
birthdayRequired: false,
|
|
||||||
birthdayMinAge: 0,
|
|
||||||
|
|
||||||
// Feature-set, apparently, not everything here is reported...
|
|
||||||
shoutAvailable: false,
|
|
||||||
pleromaChatMessagesAvailable: false,
|
|
||||||
pleromaCustomEmojiReactionsAvailable: false,
|
|
||||||
pleromaBookmarkFoldersAvailable: false,
|
|
||||||
pleromaPublicFavouritesAvailable: true,
|
|
||||||
statusNotificationTypeAvailable: true,
|
|
||||||
gopherAvailable: false,
|
|
||||||
mediaProxyAvailable: false,
|
|
||||||
suggestionsEnabled: false,
|
|
||||||
suggestionsWeb: '',
|
|
||||||
quotingAvailable: false,
|
|
||||||
groupActorAvailable: false,
|
|
||||||
blockExpiration: false,
|
|
||||||
localBubbleInstances: [], // Akkoma
|
|
||||||
|
|
||||||
// Html stuff
|
|
||||||
instanceSpecificPanelContent: '',
|
|
||||||
tos: '',
|
|
||||||
|
|
||||||
// Version Information
|
|
||||||
backendVersion: '',
|
|
||||||
backendRepository: '',
|
|
||||||
frontendVersion: '',
|
|
||||||
|
|
||||||
pollsAvailable: false,
|
|
||||||
pollLimits: {
|
|
||||||
max_options: 4,
|
|
||||||
max_option_chars: 255,
|
|
||||||
min_expiration: 60,
|
|
||||||
max_expiration: 60 * 60 * 24,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
const loadAnnotations = (lang) => {
|
|
||||||
return annotationsLoader[lang]().then((k) => k.default)
|
|
||||||
}
|
|
||||||
|
|
||||||
const injectAnnotations = (emoji, annotations) => {
|
|
||||||
const availableLangs = Object.keys(annotations)
|
|
||||||
|
|
||||||
return {
|
|
||||||
...emoji,
|
|
||||||
annotations: availableLangs.reduce((acc, cur) => {
|
|
||||||
acc[cur] = annotations[cur][emoji.replacement]
|
|
||||||
return acc
|
|
||||||
}, {}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const injectRegionalIndicators = (groups) => {
|
|
||||||
groups.symbols.push(...REGIONAL_INDICATORS)
|
|
||||||
return groups
|
|
||||||
}
|
|
||||||
|
|
||||||
const instance = {
|
|
||||||
state: defaultState,
|
|
||||||
mutations: {
|
|
||||||
setInstanceOption(state, { name, value }) {
|
|
||||||
if (typeof value !== 'undefined') {
|
|
||||||
state[name] = value
|
|
||||||
}
|
|
||||||
},
|
|
||||||
setKnownDomains(state, domains) {
|
|
||||||
state.knownDomains = domains
|
|
||||||
},
|
|
||||||
setUnicodeEmojiAnnotations(state, { lang, annotations }) {
|
|
||||||
state.unicodeEmojiAnnotations[lang] = annotations
|
|
||||||
},
|
|
||||||
},
|
|
||||||
getters: {
|
|
||||||
instanceDefaultConfig(state) {
|
|
||||||
return instanceDefaultProperties
|
|
||||||
.map((key) => [key, state[key]])
|
|
||||||
.reduce((acc, [key, value]) => ({ ...acc, [key]: value }), {})
|
|
||||||
},
|
|
||||||
groupedCustomEmojis(state) {
|
|
||||||
const packsOf = (emoji) => {
|
|
||||||
const packs = emoji.tags
|
|
||||||
.filter((k) => k.startsWith('pack:'))
|
|
||||||
.map((k) => {
|
|
||||||
const packName = k.slice(5) // remove 'pack:' prefix
|
|
||||||
return {
|
|
||||||
id: `custom-${packName}`,
|
|
||||||
text: packName,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
if (!packs.length) {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
id: 'unpacked',
|
|
||||||
},
|
|
||||||
]
|
|
||||||
} else {
|
|
||||||
return packs
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return state.customEmoji.reduce((res, emoji) => {
|
|
||||||
packsOf(emoji).forEach(({ id: packId, text: packName }) => {
|
|
||||||
if (!res[packId]) {
|
|
||||||
res[packId] = {
|
|
||||||
id: packId,
|
|
||||||
text: packName,
|
|
||||||
image: emoji.imageUrl,
|
|
||||||
emojis: [],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
res[packId].emojis.push(emoji)
|
|
||||||
})
|
|
||||||
return res
|
|
||||||
}, {})
|
|
||||||
},
|
|
||||||
standardEmojiList(state) {
|
|
||||||
return SORTED_EMOJI_GROUP_IDS.map((groupId) =>
|
|
||||||
(state.emoji[groupId] || []).map((k) =>
|
|
||||||
injectAnnotations(k, state.unicodeEmojiAnnotations),
|
|
||||||
),
|
|
||||||
).reduce((a, b) => a.concat(b), [])
|
|
||||||
},
|
|
||||||
standardEmojiGroupList(state) {
|
|
||||||
return SORTED_EMOJI_GROUP_IDS.map((groupId) => ({
|
|
||||||
id: groupId,
|
|
||||||
emojis: (state.emoji[groupId] || []).map((k) =>
|
|
||||||
injectAnnotations(k, state.unicodeEmojiAnnotations),
|
|
||||||
),
|
|
||||||
}))
|
|
||||||
},
|
|
||||||
instanceDomain(state) {
|
|
||||||
return new URL(state.server).hostname
|
|
||||||
},
|
|
||||||
remoteInteractionLink(state) {
|
|
||||||
const server = state.server.endsWith('/')
|
|
||||||
? state.server.slice(0, -1)
|
|
||||||
: state.server
|
|
||||||
const link = server + REMOTE_INTERACTION_URL
|
|
||||||
|
|
||||||
return ({ statusId, nickname }) => {
|
|
||||||
if (statusId) {
|
|
||||||
return `${link}?status_id=${statusId}`
|
|
||||||
} else {
|
|
||||||
return `${link}?nickname=${nickname}`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
actions: {
|
|
||||||
setInstanceOption({ commit, dispatch }, { name, value }) {
|
|
||||||
commit('setInstanceOption', { name, value })
|
|
||||||
switch (name) {
|
|
||||||
case 'name':
|
|
||||||
useInterfaceStore().setPageTitle()
|
|
||||||
break
|
|
||||||
case 'shoutAvailable':
|
|
||||||
if (value) {
|
|
||||||
dispatch('initializeSocket')
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
},
|
|
||||||
async getStaticEmoji({ commit }) {
|
|
||||||
try {
|
|
||||||
const values = (await import('/src/assets/emoji.json')).default
|
|
||||||
|
|
||||||
const emoji = Object.keys(values).reduce((res, groupId) => {
|
|
||||||
res[groupId] = values[groupId].map((e) => ({
|
|
||||||
displayText: e.slug,
|
|
||||||
imageUrl: false,
|
|
||||||
replacement: e.emoji,
|
|
||||||
}))
|
|
||||||
return res
|
|
||||||
}, {})
|
|
||||||
commit('setInstanceOption', {
|
|
||||||
name: 'emoji',
|
|
||||||
value: injectRegionalIndicators(emoji),
|
|
||||||
})
|
|
||||||
} catch (e) {
|
|
||||||
console.warn("Can't load static emoji\n", e)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
loadUnicodeEmojiData({ commit, state }, language) {
|
|
||||||
const langList = ensureFinalFallback(language)
|
|
||||||
|
|
||||||
return Promise.all(
|
|
||||||
langList.map(async (lang) => {
|
|
||||||
if (!state.unicodeEmojiAnnotations[lang]) {
|
|
||||||
try {
|
|
||||||
const annotations = await loadAnnotations(lang)
|
|
||||||
commit('setUnicodeEmojiAnnotations', { lang, annotations })
|
|
||||||
} catch (e) {
|
|
||||||
console.warn(
|
|
||||||
`Error loading unicode emoji annotations for ${lang}: `,
|
|
||||||
e,
|
|
||||||
)
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
},
|
|
||||||
|
|
||||||
async getCustomEmoji({ commit, state }) {
|
|
||||||
try {
|
|
||||||
let res = await window.fetch('/api/v1/pleroma/emoji')
|
|
||||||
if (!res.ok) {
|
|
||||||
res = await window.fetch('/api/pleroma/emoji.json')
|
|
||||||
}
|
|
||||||
if (res.ok) {
|
|
||||||
const result = await res.json()
|
|
||||||
const values = Array.isArray(result)
|
|
||||||
? Object.assign({}, ...result)
|
|
||||||
: result
|
|
||||||
const caseInsensitiveStrCmp = (a, b) => {
|
|
||||||
const la = a.toLowerCase()
|
|
||||||
const lb = b.toLowerCase()
|
|
||||||
return la > lb ? 1 : la < lb ? -1 : 0
|
|
||||||
}
|
|
||||||
const noPackLast = (a, b) => {
|
|
||||||
const aNull = a === ''
|
|
||||||
const bNull = b === ''
|
|
||||||
if (aNull === bNull) {
|
|
||||||
return 0
|
|
||||||
} else if (aNull && !bNull) {
|
|
||||||
return 1
|
|
||||||
} else {
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const byPackThenByName = (a, b) => {
|
|
||||||
const packOf = (emoji) =>
|
|
||||||
(emoji.tags.filter((k) => k.startsWith('pack:'))[0] || '').slice(
|
|
||||||
5,
|
|
||||||
)
|
|
||||||
const packOfA = packOf(a)
|
|
||||||
const packOfB = packOf(b)
|
|
||||||
return (
|
|
||||||
noPackLast(packOfA, packOfB) ||
|
|
||||||
caseInsensitiveStrCmp(packOfA, packOfB) ||
|
|
||||||
caseInsensitiveStrCmp(a.displayText, b.displayText)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const emoji = Object.entries(values)
|
|
||||||
.map(([key, value]) => {
|
|
||||||
const imageUrl = value.image_url
|
|
||||||
return {
|
|
||||||
displayText: key,
|
|
||||||
imageUrl: imageUrl ? state.server + imageUrl : value,
|
|
||||||
tags: imageUrl
|
|
||||||
? value.tags.sort((a, b) => (a > b ? 1 : 0))
|
|
||||||
: ['utf'],
|
|
||||||
replacement: `:${key}: `,
|
|
||||||
}
|
|
||||||
// Technically could use tags but those are kinda useless right now,
|
|
||||||
// should have been "pack" field, that would be more useful
|
|
||||||
})
|
|
||||||
.sort(byPackThenByName)
|
|
||||||
commit('setInstanceOption', { name: 'customEmoji', value: emoji })
|
|
||||||
} else {
|
|
||||||
throw res
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.warn("Can't load custom emojis\n", e)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
fetchEmoji({ dispatch, state }) {
|
|
||||||
if (!state.customEmojiFetched) {
|
|
||||||
state.customEmojiFetched = true
|
|
||||||
dispatch('getCustomEmoji')
|
|
||||||
}
|
|
||||||
if (!state.emojiFetched) {
|
|
||||||
state.emojiFetched = true
|
|
||||||
dispatch('getStaticEmoji')
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
async getKnownDomains({ commit, rootState }) {
|
|
||||||
try {
|
|
||||||
const result = await apiService.fetchKnownDomains({
|
|
||||||
credentials: rootState.users.currentUser.credentials,
|
|
||||||
})
|
|
||||||
commit('setKnownDomains', result)
|
|
||||||
} catch (e) {
|
|
||||||
console.warn("Can't load known domains\n", e)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
export default instance
|
|
||||||
|
|
@ -10,6 +10,7 @@ import {
|
||||||
} from 'lodash'
|
} from 'lodash'
|
||||||
|
|
||||||
import { declarations } from 'src/modules/config_declaration'
|
import { declarations } from 'src/modules/config_declaration'
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import { useInterfaceStore } from 'src/stores/interface.js'
|
import { useInterfaceStore } from 'src/stores/interface.js'
|
||||||
import { useOAuthStore } from 'src/stores/oauth.js'
|
import { useOAuthStore } from 'src/stores/oauth.js'
|
||||||
import { useServerSideStorageStore } from 'src/stores/serverSideStorage'
|
import { useServerSideStorageStore } from 'src/stores/serverSideStorage'
|
||||||
|
|
@ -547,7 +548,7 @@ const users = {
|
||||||
},
|
},
|
||||||
registerPushNotifications(store) {
|
registerPushNotifications(store) {
|
||||||
const token = store.state.currentUser.credentials
|
const token = store.state.currentUser.credentials
|
||||||
const vapidPublicKey = store.rootState.instance.vapidPublicKey
|
const vapidPublicKey = useInstanceStore().vapidPublicKey
|
||||||
const isEnabled = store.rootState.config.webPushNotifications
|
const isEnabled = store.rootState.config.webPushNotifications
|
||||||
const notificationVisibility =
|
const notificationVisibility =
|
||||||
store.rootState.config.notificationVisibility
|
store.rootState.config.notificationVisibility
|
||||||
|
|
@ -685,7 +686,6 @@ const users = {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const commit = store.commit
|
const commit = store.commit
|
||||||
const dispatch = store.dispatch
|
const dispatch = store.dispatch
|
||||||
const rootState = store.rootState
|
|
||||||
commit('beginLogin')
|
commit('beginLogin')
|
||||||
store.rootState.api.backendInteractor
|
store.rootState.api.backendInteractor
|
||||||
.verifyCredentials(accessToken)
|
.verifyCredentials(accessToken)
|
||||||
|
|
@ -763,7 +763,7 @@ const users = {
|
||||||
// Start fetching notifications
|
// Start fetching notifications
|
||||||
dispatch('startFetchingNotifications')
|
dispatch('startFetchingNotifications')
|
||||||
|
|
||||||
if (rootState.instance.pleromaChatMessagesAvailable) {
|
if (useInstanceStore().pleromaChatMessagesAvailable) {
|
||||||
// Start fetching chats
|
// Start fetching chats
|
||||||
dispatch('startFetchingChats')
|
dispatch('startFetchingChats')
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import bookmarkFoldersFetcher from '../../services/bookmark_folders_fetcher/bookmark_folders_fetcher.service.js'
|
import bookmarkFoldersFetcher from '../../services/bookmark_folders_fetcher/bookmark_folders_fetcher.service.js'
|
||||||
import followRequestFetcher from '../../services/follow_request_fetcher/follow_request_fetcher.service'
|
import followRequestFetcher from '../../services/follow_request_fetcher/follow_request_fetcher.service'
|
||||||
import listsFetcher from '../../services/lists_fetcher/lists_fetcher.service.js'
|
import listsFetcher from '../../services/lists_fetcher/lists_fetcher.service.js'
|
||||||
|
|
@ -55,7 +56,7 @@ const backendInteractorService = (credentials) => ({
|
||||||
},
|
},
|
||||||
|
|
||||||
startUserSocket({ store }) {
|
startUserSocket({ store }) {
|
||||||
const serv = store.rootState.instance.server.replace('http', 'ws')
|
const serv = useInstanceStore().server.replace('http', 'ws')
|
||||||
const url = getMastodonSocketURI({}, serv)
|
const url = getMastodonSocketURI({}, serv)
|
||||||
return ProcessedWS({ url, id: 'Unified', credentials })
|
return ProcessedWS({ url, id: 'Unified', credentials })
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import { useInterfaceStore } from 'src/stores/interface.js'
|
import { useInterfaceStore } from 'src/stores/interface.js'
|
||||||
import apiService from '../api/api.service.js'
|
import apiService from '../api/api.service.js'
|
||||||
import { promiseInterval } from '../promise_interval/promise_interval.js'
|
import { promiseInterval } from '../promise_interval/promise_interval.js'
|
||||||
|
|
@ -28,7 +29,7 @@ const fetchAndUpdate = ({ store, credentials, older = false, since }) => {
|
||||||
const timelineData = rootState.notifications
|
const timelineData = rootState.notifications
|
||||||
const hideMutedPosts = getters.mergedConfig.hideMutedPosts
|
const hideMutedPosts = getters.mergedConfig.hideMutedPosts
|
||||||
|
|
||||||
if (rootState.instance.pleromaChatMessagesAvailable) {
|
if (useInstanceStore().pleromaChatMessagesAvailable) {
|
||||||
mastoApiNotificationTypes.add('pleroma:chat_mention')
|
mastoApiNotificationTypes.add('pleroma:chat_mention')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import { camelCase } from 'lodash'
|
import { camelCase } from 'lodash'
|
||||||
|
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import { useInterfaceStore } from 'src/stores/interface.js'
|
import { useInterfaceStore } from 'src/stores/interface.js'
|
||||||
import apiService from '../api/api.service.js'
|
import apiService from '../api/api.service.js'
|
||||||
import { promiseInterval } from '../promise_interval/promise_interval.js'
|
import { promiseInterval } from '../promise_interval/promise_interval.js'
|
||||||
|
|
@ -76,7 +77,7 @@ const fetchAndUpdate = ({
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
if (response.errors) {
|
if (response.errors) {
|
||||||
if (timeline === 'favorites') {
|
if (timeline === 'favorites') {
|
||||||
rootState.instance.pleromaPublicFavouritesAvailable = false
|
useInstanceStore().pleromaPublicFavouritesAvailable = false
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
throw new Error(`${response.status} ${response.statusText}`)
|
throw new Error(`${response.status} ${response.statusText}`)
|
||||||
|
|
|
||||||
157
src/stores/instance.js
Normal file
157
src/stores/instance.js
Normal file
|
|
@ -0,0 +1,157 @@
|
||||||
|
import { get, set } from 'lodash'
|
||||||
|
import { defineStore } from 'pinia'
|
||||||
|
|
||||||
|
import { ensureFinalFallback } from 'src/i18n/languages.js'
|
||||||
|
import { useInterfaceStore } from 'src/stores/interface.js'
|
||||||
|
import { instanceDefaultProperties } from '../modules/config.js'
|
||||||
|
import {
|
||||||
|
instanceDefaultConfig,
|
||||||
|
staticOrApiConfigDefault,
|
||||||
|
} from '../modules/default_config_state.js'
|
||||||
|
import apiService from '../services/api/api.service.js'
|
||||||
|
|
||||||
|
const REMOTE_INTERACTION_URL = '/main/ostatus'
|
||||||
|
|
||||||
|
const defaultState = {
|
||||||
|
// Stuff from apiConfig
|
||||||
|
name: 'Pleroma FE',
|
||||||
|
registrationOpen: true,
|
||||||
|
server: 'http://localhost:4040/',
|
||||||
|
textlimit: 5000,
|
||||||
|
private: false,
|
||||||
|
federating: true,
|
||||||
|
federationPolicy: null,
|
||||||
|
themesIndex: null,
|
||||||
|
stylesIndex: null,
|
||||||
|
palettesIndex: null,
|
||||||
|
themeData: null, // used for theme editor v2
|
||||||
|
vapidPublicKey: null,
|
||||||
|
|
||||||
|
// Stuff from static/config.json
|
||||||
|
loginMethod: 'password',
|
||||||
|
disableUpdateNotification: false,
|
||||||
|
|
||||||
|
// Instance-wide configurations that should not be changed by individual users
|
||||||
|
instanceIdentity: {
|
||||||
|
...staticOrApiConfigDefault,
|
||||||
|
},
|
||||||
|
|
||||||
|
limits: {
|
||||||
|
bannerlimit: null,
|
||||||
|
avatarlimit: null,
|
||||||
|
backgroundlimit: null,
|
||||||
|
uploadlimit: null,
|
||||||
|
fieldsLimits: null,
|
||||||
|
pollLimits: {
|
||||||
|
max_options: 4,
|
||||||
|
max_option_chars: 255,
|
||||||
|
min_expiration: 60,
|
||||||
|
max_expiration: 60 * 60 * 24,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// Instance admins can override default settings for the whole instance
|
||||||
|
prefsStorage: {
|
||||||
|
...instanceDefaultConfig,
|
||||||
|
},
|
||||||
|
|
||||||
|
// Known domains list for user's domain-muting
|
||||||
|
knownDomains: [],
|
||||||
|
|
||||||
|
// Moderation stuff
|
||||||
|
staffAccounts: [],
|
||||||
|
accountActivationRequired: null,
|
||||||
|
accountApprovalRequired: null,
|
||||||
|
birthdayRequired: false,
|
||||||
|
birthdayMinAge: 0,
|
||||||
|
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
|
||||||
|
},
|
||||||
|
|
||||||
|
// Html stuff
|
||||||
|
instanceSpecificPanelContent: '',
|
||||||
|
tos: '',
|
||||||
|
|
||||||
|
// Version Information
|
||||||
|
backendVersion: '',
|
||||||
|
backendRepository: '',
|
||||||
|
frontendVersion: '',
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useInstanceStore = defineStore('instance', {
|
||||||
|
state: () => ({ ...defaultState }),
|
||||||
|
getters: {
|
||||||
|
instanceDefaultConfig(state) {
|
||||||
|
return instanceDefaultProperties
|
||||||
|
.map((key) => [key, state[key]])
|
||||||
|
.reduce((acc, [key, value]) => ({ ...acc, [key]: value }), {})
|
||||||
|
},
|
||||||
|
instanceDomain(state) {
|
||||||
|
return new URL(this.server).hostname
|
||||||
|
},
|
||||||
|
remoteInteractionLink(state) {
|
||||||
|
const server = this.server.endsWith('/')
|
||||||
|
? this.server.slice(0, -1)
|
||||||
|
: this.server
|
||||||
|
const link = server + REMOTE_INTERACTION_URL
|
||||||
|
|
||||||
|
return ({ statusId, nickname }) => {
|
||||||
|
if (statusId) {
|
||||||
|
return `${link}?status_id=${statusId}`
|
||||||
|
} else {
|
||||||
|
return `${link}?nickname=${nickname}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
set({ path, value }) {
|
||||||
|
if (get(defaultState, path) === undefined)
|
||||||
|
console.error(`Unknown instance option ${path}, value: ${value}`)
|
||||||
|
set(this, path, value)
|
||||||
|
switch (name) {
|
||||||
|
case 'name':
|
||||||
|
useInterfaceStore().setPageTitle()
|
||||||
|
break
|
||||||
|
case 'shoutAvailable':
|
||||||
|
if (value) {
|
||||||
|
window.vuex.dispatch('initializeSocket')
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async getKnownDomains() {
|
||||||
|
try {
|
||||||
|
this.knownDomains = await apiService.fetchKnownDomains({
|
||||||
|
credentials: window.vuex.state.users.currentUser.credentials,
|
||||||
|
})
|
||||||
|
} catch (e) {
|
||||||
|
console.warn("Can't load known domains\n", e)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
@ -5,6 +5,7 @@ import {
|
||||||
generatePreset,
|
generatePreset,
|
||||||
} from 'src/services/theme_data/theme_data.service.js'
|
} from 'src/services/theme_data/theme_data.service.js'
|
||||||
import { convertTheme2To3 } from 'src/services/theme_data/theme2_to_theme3.js'
|
import { convertTheme2To3 } from 'src/services/theme_data/theme2_to_theme3.js'
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import {
|
import {
|
||||||
applyTheme,
|
applyTheme,
|
||||||
getResourcesIndex,
|
getResourcesIndex,
|
||||||
|
|
@ -86,7 +87,7 @@ export const useInterfaceStore = defineStore('interface', {
|
||||||
},
|
},
|
||||||
setPageTitle(option = '') {
|
setPageTitle(option = '') {
|
||||||
try {
|
try {
|
||||||
document.title = `${option} ${window.vuex.state.instance.name}`
|
document.title = `${option} ${window.vuex.useInstanceStore().name}`
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`${error}`)
|
console.error(`${error}`)
|
||||||
}
|
}
|
||||||
|
|
@ -385,14 +386,14 @@ export const useInterfaceStore = defineStore('interface', {
|
||||||
}
|
}
|
||||||
|
|
||||||
const { style: instanceStyleName, palette: instancePaletteName } =
|
const { style: instanceStyleName, palette: instancePaletteName } =
|
||||||
window.vuex.state.instance
|
window.vuex.useInstanceStore()
|
||||||
|
|
||||||
let {
|
let {
|
||||||
theme: instanceThemeV2Name,
|
theme: instanceThemeV2Name,
|
||||||
themesIndex,
|
themesIndex,
|
||||||
stylesIndex,
|
stylesIndex,
|
||||||
palettesIndex,
|
palettesIndex,
|
||||||
} = window.vuex.state.instance
|
} = window.vuex.useInstanceStore()
|
||||||
|
|
||||||
const {
|
const {
|
||||||
style: userStyleName,
|
style: userStyleName,
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import {
|
||||||
getClientToken,
|
getClientToken,
|
||||||
verifyAppToken,
|
verifyAppToken,
|
||||||
} from 'src/services/new_api/oauth.js'
|
} from 'src/services/new_api/oauth.js'
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
|
|
||||||
// status codes about verifyAppToken (GET /api/v1/apps/verify_credentials)
|
// status codes about verifyAppToken (GET /api/v1/apps/verify_credentials)
|
||||||
const isAppTokenRejected = (error) =>
|
const isAppTokenRejected = (error) =>
|
||||||
|
|
@ -61,8 +62,7 @@ export const useOAuthStore = defineStore('oauth', {
|
||||||
this.userToken = false
|
this.userToken = false
|
||||||
},
|
},
|
||||||
async createApp() {
|
async createApp() {
|
||||||
const { state } = window.vuex
|
const instance = useInstanceStore().server
|
||||||
const instance = state.instance.server
|
|
||||||
const app = await createApp(instance)
|
const app = await createApp(instance)
|
||||||
this.setClientData(app)
|
this.setClientData(app)
|
||||||
return app
|
return app
|
||||||
|
|
@ -81,8 +81,7 @@ export const useOAuthStore = defineStore('oauth', {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async getAppToken() {
|
async getAppToken() {
|
||||||
const { state } = window.vuex
|
const instance = useInstanceStore().server
|
||||||
const instance = state.instance.server
|
|
||||||
const res = await getClientToken({
|
const res = await getClientToken({
|
||||||
clientId: this.clientId,
|
clientId: this.clientId,
|
||||||
clientSecret: this.clientSecret,
|
clientSecret: this.clientSecret,
|
||||||
|
|
@ -94,11 +93,10 @@ export const useOAuthStore = defineStore('oauth', {
|
||||||
/// Use this if you want to ensure the app is still valid to use.
|
/// Use this if you want to ensure the app is still valid to use.
|
||||||
/// @return {string} The access token to the app (not attached to any user)
|
/// @return {string} The access token to the app (not attached to any user)
|
||||||
async ensureAppToken() {
|
async ensureAppToken() {
|
||||||
const { state } = window.vuex
|
|
||||||
if (this.appToken) {
|
if (this.appToken) {
|
||||||
try {
|
try {
|
||||||
await verifyAppToken({
|
await verifyAppToken({
|
||||||
instance: state.instance.server,
|
instance: useInstanceStore().server,
|
||||||
appToken: this.appToken,
|
appToken: this.appToken,
|
||||||
})
|
})
|
||||||
return this.appToken
|
return this.appToken
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue