Merge branch 'users-statuses-pinia' into shigusegubu-themes3
This commit is contained in:
commit
f62e323400
216 changed files with 7262 additions and 5413 deletions
1
changelog.d/actions-extra-tap.fix
Normal file
1
changelog.d/actions-extra-tap.fix
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
fixed tapping "Mute..." and "Change visiblity" (admin action) in extra status actions closing the dropdown
|
||||||
1
changelog.d/config-migration.fix
Normal file
1
changelog.d/config-migration.fix
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Fix legacy settings migration being discarded after it ran.
|
||||||
1
changelog.d/fix-chat-post.fix
Normal file
1
changelog.d/fix-chat-post.fix
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Fix error dialog when posting in chat
|
||||||
1
changelog.d/fix-domain-mute.fix
Normal file
1
changelog.d/fix-domain-mute.fix
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
domain mute fixedw
|
||||||
1
changelog.d/followers-list.fix
Normal file
1
changelog.d/followers-list.fix
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Fix followers list showing followed users as non-followed
|
||||||
1
changelog.d/media-proxy-sw-cache.fix
Normal file
1
changelog.d/media-proxy-sw-cache.fix
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Prevent service worker from caching media-proxy responses
|
||||||
1
changelog.d/moderation-tools.fix
Normal file
1
changelog.d/moderation-tools.fix
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
fix moderation tools button possibly not appearing for admins
|
||||||
1
changelog.d/moderation.fix
Normal file
1
changelog.d/moderation.fix
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Fixed moderation actions requiring confirmation closing user popover
|
||||||
1
changelog.d/streaming.add
Normal file
1
changelog.d/streaming.add
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
More timelines now can utilize WebSocket streaming
|
||||||
1
changelog.d/streaming.fix
Normal file
1
changelog.d/streaming.fix
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
switches between streaming and polling should be more reliable now
|
||||||
1
changelog.d/streaming_indicator.add
Normal file
1
changelog.d/streaming_indicator.add
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Added an indicator next to instance's name showing WebSocket connection status (if enabled)
|
||||||
1
changelog.d/theme-index-html-fallback.fix
Normal file
1
changelog.d/theme-index-html-fallback.fix
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Fix theme lists failing to load when custom resource indexes are unavailable
|
||||||
1
changelog.d/themes2-font.fix
Normal file
1
changelog.d/themes2-font.fix
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Fix Themes 2.0 applying incorrect fonts
|
||||||
1
changelog.d/themes3.fix
Normal file
1
changelog.d/themes3.fix
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Fixed themes 3 not loading in appearance tab
|
||||||
|
|
@ -21,6 +21,7 @@ import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.j
|
||||||
import { useInterfaceStore } from 'src/stores/interface.js'
|
import { useInterfaceStore } from 'src/stores/interface.js'
|
||||||
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
||||||
import { useShoutStore } from 'src/stores/shout.js'
|
import { useShoutStore } from 'src/stores/shout.js'
|
||||||
|
import { useUsersStore } from 'src/stores/users.js'
|
||||||
|
|
||||||
// Helper to unwrap reactive proxies
|
// Helper to unwrap reactive proxies
|
||||||
window.toValue = (x) => JSON.parse(JSON.stringify(x))
|
window.toValue = (x) => JSON.parse(JSON.stringify(x))
|
||||||
|
|
@ -153,11 +154,8 @@ export default {
|
||||||
...(navbarColumnStretch ? ['-column-stretch'] : []),
|
...(navbarColumnStretch ? ['-column-stretch'] : []),
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
currentUser() {
|
|
||||||
return this.$store.state.users.currentUser
|
|
||||||
},
|
|
||||||
userBackground() {
|
userBackground() {
|
||||||
return this.currentUser.background_image
|
return this.currentUser?.background_image
|
||||||
},
|
},
|
||||||
foreignProfileBackground() {
|
foreignProfileBackground() {
|
||||||
return (
|
return (
|
||||||
|
|
@ -246,6 +244,7 @@ export default {
|
||||||
'styleDataUsed',
|
'styleDataUsed',
|
||||||
'layoutType',
|
'layoutType',
|
||||||
]),
|
]),
|
||||||
|
...mapState(useUsersStore, ['currentUser']),
|
||||||
...mapState(useInstanceStore, ['styleDataUsed']),
|
...mapState(useInstanceStore, ['styleDataUsed']),
|
||||||
...mapState(useInstanceCapabilitiesStore, [
|
...mapState(useInstanceCapabilitiesStore, [
|
||||||
'suggestionsEnabled',
|
'suggestionsEnabled',
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@
|
||||||
class="column -scrollable"
|
class="column -scrollable"
|
||||||
:class="{ '-show-scrollbar': showScrollbars }"
|
:class="{ '-show-scrollbar': showScrollbars }"
|
||||||
>
|
>
|
||||||
<user-panel />
|
<UserPanel />
|
||||||
<template v-if="layoutType !== 'mobile'">
|
<template v-if="layoutType !== 'mobile'">
|
||||||
<NavPanel />
|
<NavPanel />
|
||||||
<InstanceSpecificPanel v-if="showInstanceSpecificPanel" />
|
<InstanceSpecificPanel v-if="showInstanceSpecificPanel" />
|
||||||
|
|
|
||||||
|
|
@ -63,10 +63,11 @@ export const paramsString = (params = {}) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const promisedRequest = async ({
|
export const promisedRequest = async ({
|
||||||
method,
|
method = 'GET',
|
||||||
url,
|
url,
|
||||||
payload,
|
payload,
|
||||||
formData,
|
formData,
|
||||||
|
forceContentType,
|
||||||
cache,
|
cache,
|
||||||
credentials,
|
credentials,
|
||||||
headers = {},
|
headers = {},
|
||||||
|
|
@ -75,7 +76,7 @@ export const promisedRequest = async ({
|
||||||
method,
|
method,
|
||||||
credentials: 'same-origin',
|
credentials: 'same-origin',
|
||||||
headers: {
|
headers: {
|
||||||
Accept: 'application/json',
|
Accept: forceContentType ?? 'application/json',
|
||||||
...headers,
|
...headers,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
@ -110,7 +111,7 @@ export const promisedRequest = async ({
|
||||||
)
|
)
|
||||||
if (contentLength === 0) return null
|
if (contentLength === 0) return null
|
||||||
|
|
||||||
switch (contentType) {
|
switch (forceContentType ?? contentType) {
|
||||||
case 'text/plain':
|
case 'text/plain':
|
||||||
return await response.text()
|
return await response.text()
|
||||||
case 'application/json':
|
case 'application/json':
|
||||||
|
|
@ -123,7 +124,7 @@ export const promisedRequest = async ({
|
||||||
const { ok, status } = response
|
const { ok, status } = response
|
||||||
|
|
||||||
if (ok) {
|
if (ok) {
|
||||||
return { response, status, data }
|
return { response, status, data, timestamp: Date.now() }
|
||||||
} else {
|
} else {
|
||||||
throw new StatusCodeError(response.status, data, { url, options }, response)
|
throw new StatusCodeError(response.status, data, { url, options }, response)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,12 +13,12 @@ const MASTODON_REGISTRATION_URL = '/api/v1/accounts'
|
||||||
const MASTODON_PASSWORD_RESET_URL = ({ email }) =>
|
const MASTODON_PASSWORD_RESET_URL = ({ email }) =>
|
||||||
`/auth/password${paramsString({ email })}`
|
`/auth/password${paramsString({ email })}`
|
||||||
|
|
||||||
const MASTODON_FOLLOWING_URL = (
|
export const MASTODON_FOLLOWING_URL = (
|
||||||
id,
|
id,
|
||||||
{ minId, maxId, sinceId, limit, withRelationships },
|
{ minId, maxId, sinceId, limit, withRelationships },
|
||||||
) =>
|
) =>
|
||||||
`/api/v1/accounts/${id}/following${paramsString({ minId, maxId, sinceId, limit, withRelationships })}`
|
`/api/v1/accounts/${id}/following${paramsString({ minId, maxId, sinceId, limit, withRelationships })}`
|
||||||
const MASTODON_FOLLOWERS_URL = (
|
export const MASTODON_FOLLOWERS_URL = (
|
||||||
id,
|
id,
|
||||||
{ minId, maxId, sinceId, limit, withRelationships },
|
{ minId, maxId, sinceId, limit, withRelationships },
|
||||||
) =>
|
) =>
|
||||||
|
|
@ -26,15 +26,17 @@ const MASTODON_FOLLOWERS_URL = (
|
||||||
|
|
||||||
export const MASTODON_STATUS_URL = (id) => `/api/v1/statuses/${id}`
|
export const MASTODON_STATUS_URL = (id) => `/api/v1/statuses/${id}`
|
||||||
const MASTODON_STATUS_CONTEXT_URL = (id) => `/api/v1/statuses/${id}/context`
|
const MASTODON_STATUS_CONTEXT_URL = (id) => `/api/v1/statuses/${id}/context`
|
||||||
const MASTODON_STATUS_SOURCE_URL = (id) => `/api/v1/statuses/${id}/source`
|
export const MASTODON_STATUS_SOURCE_URL = (id) =>
|
||||||
const MASTODON_STATUS_HISTORY_URL = (id) => `/api/v1/statuses/${id}/history`
|
`/api/v1/statuses/${id}/source`
|
||||||
|
export const MASTODON_STATUS_HISTORY_URL = (id) =>
|
||||||
|
`/api/v1/statuses/${id}/history`
|
||||||
const MASTODON_USER_URL = '/api/v1/accounts'
|
const MASTODON_USER_URL = '/api/v1/accounts'
|
||||||
const MASTODON_USER_LOOKUP_URL = ({ acct }) =>
|
const MASTODON_USER_LOOKUP_URL = ({ acct }) =>
|
||||||
`/api/v1/accounts/lookup${paramsString({ acct })}`
|
`/api/v1/accounts/lookup${paramsString({ acct })}`
|
||||||
const MASTODON_POLL_URL = (id = '') => `/api/v1/polls/${id}`
|
const MASTODON_POLL_URL = (id = '') => `/api/v1/polls/${id}`
|
||||||
const MASTODON_STATUS_FAVORITEDBY_URL = (id) =>
|
export const MASTODON_STATUS_FAVORITEDBY_URL = (id) =>
|
||||||
`/api/v1/statuses/${id}/favourited_by`
|
`/api/v1/statuses/${id}/favourited_by`
|
||||||
const MASTODON_STATUS_REBLOGGEDBY_URL = (id) =>
|
export const MASTODON_STATUS_REBLOGGEDBY_URL = (id) =>
|
||||||
`/api/v1/statuses/${id}/reblogged_by`
|
`/api/v1/statuses/${id}/reblogged_by`
|
||||||
const MASTODON_SEARCH_2 = ({
|
const MASTODON_SEARCH_2 = ({
|
||||||
q,
|
q,
|
||||||
|
|
@ -51,7 +53,7 @@ const MASTODON_SEARCH_2 = ({
|
||||||
const MASTODON_USER_SEARCH_URL = ({ q, resolve }) =>
|
const MASTODON_USER_SEARCH_URL = ({ q, resolve }) =>
|
||||||
`/api/v1/accounts/search${paramsString({ q, resolve })}`
|
`/api/v1/accounts/search${paramsString({ q, resolve })}`
|
||||||
const MASTODON_KNOWN_DOMAIN_LIST_URL = '/api/v1/instance/peers'
|
const MASTODON_KNOWN_DOMAIN_LIST_URL = '/api/v1/instance/peers'
|
||||||
const PLEROMA_EMOJI_REACTIONS_URL = (id) =>
|
export const PLEROMA_EMOJI_REACTIONS_URL = (id) =>
|
||||||
`/api/v1/pleroma/statuses/${id}/reactions`
|
`/api/v1/pleroma/statuses/${id}/reactions`
|
||||||
const PLEROMA_SCROBBLES_URL = (id, { maxId, sinceId, minId, limit, offset }) =>
|
const PLEROMA_SCROBBLES_URL = (id, { maxId, sinceId, minId, limit, offset }) =>
|
||||||
`/api/v1/pleroma/accounts/${id}/scrobbles${paramsString({ maxId, sinceId, minId, limit, offset })}`
|
`/api/v1/pleroma/accounts/${id}/scrobbles${paramsString({ maxId, sinceId, minId, limit, offset })}`
|
||||||
|
|
@ -117,9 +119,17 @@ export const fetchUserByName = ({ name, credentials }) =>
|
||||||
|
|
||||||
export const fetchFriends = ({ id, maxId, sinceId, limit = 20, credentials }) =>
|
export const fetchFriends = ({ id, maxId, sinceId, limit = 20, credentials }) =>
|
||||||
promisedRequest({
|
promisedRequest({
|
||||||
url: MASTODON_FOLLOWING_URL(id, { maxId, sinceId, limit }),
|
url: MASTODON_FOLLOWING_URL(id, {
|
||||||
|
maxId,
|
||||||
|
sinceId,
|
||||||
|
limit,
|
||||||
|
withRelationships: true,
|
||||||
|
}),
|
||||||
credentials,
|
credentials,
|
||||||
}).then(({ data, ...rest }) => ({ ...rest, data: data.map(parseUser) }))
|
}).then(({ data, ...rest }) => ({
|
||||||
|
...rest,
|
||||||
|
data: data.map(parseUser),
|
||||||
|
}))
|
||||||
|
|
||||||
export const fetchFollowers = ({
|
export const fetchFollowers = ({
|
||||||
id,
|
id,
|
||||||
|
|
@ -136,7 +146,10 @@ export const fetchFollowers = ({
|
||||||
withRelationships: true,
|
withRelationships: true,
|
||||||
}),
|
}),
|
||||||
credentials,
|
credentials,
|
||||||
}).then(({ data, ...rest }) => ({ ...rest, data: data.map(parseUser) }))
|
}).then(({ data, ...rest }) => ({
|
||||||
|
...rest,
|
||||||
|
data: data.map(parseUser),
|
||||||
|
}))
|
||||||
|
|
||||||
export const fetchConversation = ({ id, credentials }) =>
|
export const fetchConversation = ({ id, credentials }) =>
|
||||||
promisedRequest({
|
promisedRequest({
|
||||||
|
|
@ -163,15 +176,18 @@ export const fetchStatusSource = ({ id, credentials }) =>
|
||||||
credentials,
|
credentials,
|
||||||
}).then(({ data, ...rest }) => ({ ...rest, data: parseSource(data) }))
|
}).then(({ data, ...rest }) => ({ ...rest, data: parseSource(data) }))
|
||||||
|
|
||||||
export const fetchStatusHistory = ({ status, credentials }) =>
|
export const fetchStatusHistory = ({ id, credentials }) =>
|
||||||
promisedRequest({
|
promisedRequest({
|
||||||
url: MASTODON_STATUS_HISTORY_URL(status.id),
|
url: MASTODON_STATUS_HISTORY_URL(id),
|
||||||
credentials,
|
credentials,
|
||||||
}).then(({ data, ...rest }) => {
|
}).then(({ data, ...rest }) => {
|
||||||
return [...data].reverse().map((item) => {
|
return {
|
||||||
item.originalStatus = status
|
...rest,
|
||||||
return { ...rest, data: parseStatus(item) }
|
data: [...data].reverse().map((item) => {
|
||||||
})
|
item.originalStatus = status
|
||||||
|
return parseStatus(item)
|
||||||
|
}),
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
export const listEmojiPacks = ({ page, pageSize, credentials }) =>
|
export const listEmojiPacks = ({ page, pageSize, credentials }) =>
|
||||||
|
|
|
||||||
|
|
@ -115,6 +115,7 @@ export const fetchTimeline = ({
|
||||||
publicAndExternal: MASTODON_PUBLIC_TIMELINE,
|
publicAndExternal: MASTODON_PUBLIC_TIMELINE,
|
||||||
dms: MASTODON_DIRECT_MESSAGES_TIMELINE_URL,
|
dms: MASTODON_DIRECT_MESSAGES_TIMELINE_URL,
|
||||||
user: MASTODON_USER_TIMELINE_URL,
|
user: MASTODON_USER_TIMELINE_URL,
|
||||||
|
userPinned: MASTODON_USER_TIMELINE_URL,
|
||||||
media: MASTODON_USER_TIMELINE_URL,
|
media: MASTODON_USER_TIMELINE_URL,
|
||||||
list: MASTODON_LIST_TIMELINE_URL,
|
list: MASTODON_LIST_TIMELINE_URL,
|
||||||
favorites: MASTODON_USER_FAVORITES_TIMELINE_URL,
|
favorites: MASTODON_USER_FAVORITES_TIMELINE_URL,
|
||||||
|
|
@ -130,6 +131,7 @@ export const fetchTimeline = ({
|
||||||
|
|
||||||
const twoArgs = new Set([
|
const twoArgs = new Set([
|
||||||
'user',
|
'user',
|
||||||
|
'userPinned',
|
||||||
'media',
|
'media',
|
||||||
'list',
|
'list',
|
||||||
'publicFavorites',
|
'publicFavorites',
|
||||||
|
|
@ -147,6 +149,7 @@ export const fetchTimeline = ({
|
||||||
const id = (() => {
|
const id = (() => {
|
||||||
switch (timeline) {
|
switch (timeline) {
|
||||||
case 'user':
|
case 'user':
|
||||||
|
case 'userPinned':
|
||||||
case 'media':
|
case 'media':
|
||||||
return userId
|
return userId
|
||||||
case 'list':
|
case 'list':
|
||||||
|
|
@ -163,6 +166,9 @@ export const fetchTimeline = ({
|
||||||
if (timeline === 'media') {
|
if (timeline === 'media') {
|
||||||
params.onlyMedia = true
|
params.onlyMedia = true
|
||||||
}
|
}
|
||||||
|
if (timeline === 'userPinned') {
|
||||||
|
params.pinned = true
|
||||||
|
}
|
||||||
if (timeline === 'public') {
|
if (timeline === 'public') {
|
||||||
params.local = true
|
params.local = true
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ const CHANGE_PASSWORD_URL = '/api/pleroma/change_password'
|
||||||
const MOVE_ACCOUNT_URL = '/api/pleroma/move_account'
|
const MOVE_ACCOUNT_URL = '/api/pleroma/move_account'
|
||||||
const ALIASES_URL = '/api/pleroma/aliases'
|
const ALIASES_URL = '/api/pleroma/aliases'
|
||||||
const NOTIFICATION_SETTINGS_URL = '/api/pleroma/notification_settings'
|
const NOTIFICATION_SETTINGS_URL = '/api/pleroma/notification_settings'
|
||||||
const NOTIFICATION_READ_URL = '/api/v1/pleroma/notifications/read'
|
export const NOTIFICATION_READ_URL = '/api/v1/pleroma/notifications/read'
|
||||||
|
|
||||||
const MFA_SETTINGS_URL = '/api/pleroma/accounts/mfa'
|
const MFA_SETTINGS_URL = '/api/pleroma/accounts/mfa'
|
||||||
const MFA_BACKUP_CODES_URL = '/api/pleroma/accounts/mfa/backup_codes'
|
const MFA_BACKUP_CODES_URL = '/api/pleroma/accounts/mfa/backup_codes'
|
||||||
|
|
@ -27,15 +27,16 @@ const MFA_SETUP_OTP_URL = '/api/pleroma/accounts/mfa/setup/totp'
|
||||||
const MFA_CONFIRM_OTP_URL = '/api/pleroma/accounts/mfa/confirm/totp'
|
const MFA_CONFIRM_OTP_URL = '/api/pleroma/accounts/mfa/confirm/totp'
|
||||||
const MFA_DISABLE_OTP_URL = '/api/pleroma/accounts/mfa/totp'
|
const MFA_DISABLE_OTP_URL = '/api/pleroma/accounts/mfa/totp'
|
||||||
|
|
||||||
const MASTODON_DISMISS_NOTIFICATION_URL = (id) =>
|
export const MASTODON_DISMISS_NOTIFICATION_URL = (id) =>
|
||||||
`/api/v1/notifications/${id}/dismiss`
|
`/api/v1/notifications/${id}/dismiss`
|
||||||
const MASTODON_FAVORITE_URL = (id) => `/api/v1/statuses/${id}/favourite`
|
export const MASTODON_FAVORITE_URL = (id) => `/api/v1/statuses/${id}/favourite`
|
||||||
const MASTODON_UNFAVORITE_URL = (id) => `/api/v1/statuses/${id}/unfavourite`
|
export const MASTODON_UNFAVORITE_URL = (id) =>
|
||||||
const MASTODON_RETWEET_URL = (id) => `/api/v1/statuses/${id}/reblog`
|
`/api/v1/statuses/${id}/unfavourite`
|
||||||
const MASTODON_UNRETWEET_URL = (id) => `/api/v1/statuses/${id}/unreblog`
|
export const MASTODON_RETWEET_URL = (id) => `/api/v1/statuses/${id}/reblog`
|
||||||
const MASTODON_DELETE_URL = (id) => `/api/v1/statuses/${id}`
|
export const MASTODON_UNRETWEET_URL = (id) => `/api/v1/statuses/${id}/unreblog`
|
||||||
const MASTODON_FOLLOW_URL = (id) => `/api/v1/accounts/${id}/follow`
|
export const MASTODON_DELETE_URL = (id) => `/api/v1/statuses/${id}`
|
||||||
const MASTODON_UNFOLLOW_URL = (id) => `/api/v1/accounts/${id}/unfollow`
|
export const MASTODON_FOLLOW_URL = (id) => `/api/v1/accounts/${id}/follow`
|
||||||
|
export const MASTODON_UNFOLLOW_URL = (id) => `/api/v1/accounts/${id}/unfollow`
|
||||||
|
|
||||||
const MASTODON_FOLLOW_REQUESTS_URL = '/api/v1/follow_requests'
|
const MASTODON_FOLLOW_REQUESTS_URL = '/api/v1/follow_requests'
|
||||||
const MASTODON_APPROVE_USER_URL = (id) =>
|
const MASTODON_APPROVE_USER_URL = (id) =>
|
||||||
|
|
@ -43,49 +44,54 @@ const MASTODON_APPROVE_USER_URL = (id) =>
|
||||||
const MASTODON_DENY_USER_URL = (id) => `/api/v1/follow_requests/${id}/reject`
|
const MASTODON_DENY_USER_URL = (id) => `/api/v1/follow_requests/${id}/reject`
|
||||||
const MASTODON_USER_RELATIONSHIPS_URL = ({ id, withSuspended }) =>
|
const MASTODON_USER_RELATIONSHIPS_URL = ({ id, withSuspended }) =>
|
||||||
`/api/v1/accounts/relationships/${paramsString({ id, withSuspended })}`
|
`/api/v1/accounts/relationships/${paramsString({ id, withSuspended })}`
|
||||||
const MASTODON_USER_IN_LISTS = (id) => `/api/v1/accounts/${id}/lists`
|
export const MASTODON_USER_IN_LISTS = (id) => `/api/v1/accounts/${id}/lists`
|
||||||
export const MASTODON_LIST_URL = (id = '') => `/api/v1/lists/${id}`
|
export const MASTODON_LIST_URL = (id = '') => `/api/v1/lists/${id}`
|
||||||
export const MASTODON_LIST_ACCOUNTS_URL = (id) => `/api/v1/lists/${id}/accounts`
|
export const MASTODON_LIST_ACCOUNTS_URL = (id) => `/api/v1/lists/${id}/accounts`
|
||||||
const MASTODON_USER_BLOCKS_URL = ({
|
export const MASTODON_USER_BLOCKS_URL = ({
|
||||||
maxId,
|
maxId,
|
||||||
sinceId,
|
sinceId,
|
||||||
limit,
|
limit,
|
||||||
withRelationships,
|
withRelationships,
|
||||||
}) =>
|
}) =>
|
||||||
`/api/v1/blocks/${paramsString({ maxId, sinceId, limit, withRelationships })}`
|
`/api/v1/blocks/${paramsString({ maxId, sinceId, limit, withRelationships })}`
|
||||||
const MASTODON_USER_MUTES_URL = ({
|
export const MASTODON_USER_MUTES_URL = ({
|
||||||
maxId,
|
maxId,
|
||||||
sinceId,
|
sinceId,
|
||||||
limit,
|
limit,
|
||||||
withRelationships,
|
withRelationships,
|
||||||
}) =>
|
}) =>
|
||||||
`/api/v1/mutes/${paramsString({ maxId, sinceId, limit, withRelationships })}`
|
`/api/v1/mutes/${paramsString({ maxId, sinceId, limit, withRelationships })}`
|
||||||
const MASTODON_BLOCK_USER_URL = (id) => `/api/v1/accounts/${id}/block`
|
export const MASTODON_BLOCK_USER_URL = (id) => `/api/v1/accounts/${id}/block`
|
||||||
const MASTODON_UNBLOCK_USER_URL = (id) => `/api/v1/accounts/${id}/unblock`
|
export const MASTODON_UNBLOCK_USER_URL = (id) =>
|
||||||
const MASTODON_MUTE_USER_URL = (id) => `/api/v1/accounts/${id}/mute`
|
`/api/v1/accounts/${id}/unblock`
|
||||||
const MASTODON_UNMUTE_USER_URL = (id) => `/api/v1/accounts/${id}/unmute`
|
export const MASTODON_MUTE_USER_URL = (id) => `/api/v1/accounts/${id}/mute`
|
||||||
const MASTODON_REMOVE_USER_FROM_FOLLOWERS = (id) =>
|
export const MASTODON_UNMUTE_USER_URL = (id) => `/api/v1/accounts/${id}/unmute`
|
||||||
|
export const MASTODON_REMOVE_USER_FROM_FOLLOWERS_URL = (id) =>
|
||||||
`/api/v1/accounts/${id}/remove_from_followers`
|
`/api/v1/accounts/${id}/remove_from_followers`
|
||||||
const MASTODON_USER_NOTE_URL = (id) => `/api/v1/accounts/${id}/note`
|
export const MASTODON_USER_NOTE_URL = (id) => `/api/v1/accounts/${id}/note`
|
||||||
const MASTODON_BOOKMARK_STATUS_URL = (id) => `/api/v1/statuses/${id}/bookmark`
|
export const MASTODON_BOOKMARK_STATUS_URL = (id) =>
|
||||||
const MASTODON_UNBOOKMARK_STATUS_URL = (id) =>
|
`/api/v1/statuses/${id}/bookmark`
|
||||||
|
export const MASTODON_UNBOOKMARK_STATUS_URL = (id) =>
|
||||||
`/api/v1/statuses/${id}/unbookmark`
|
`/api/v1/statuses/${id}/unbookmark`
|
||||||
const MASTODON_POST_STATUS_URL = '/api/v1/statuses'
|
const MASTODON_POST_STATUS_URL = '/api/v1/statuses'
|
||||||
const MASTODON_MEDIA_UPLOAD_URL = '/api/v1/media'
|
const MASTODON_MEDIA_UPLOAD_URL = '/api/v1/media'
|
||||||
const MASTODON_VOTE_URL = (id) => `/api/v1/polls/${id}/votes`
|
const MASTODON_VOTE_URL = (id) => `/api/v1/polls/${id}/votes`
|
||||||
const MASTODON_PROFILE_UPDATE_URL = '/api/v1/accounts/update_credentials'
|
const MASTODON_PROFILE_UPDATE_URL = '/api/v1/accounts/update_credentials'
|
||||||
const MASTODON_REPORT_USER_URL = '/api/v1/reports'
|
const MASTODON_REPORT_USER_URL = '/api/v1/reports'
|
||||||
const MASTODON_PIN_OWN_STATUS = (id) => `/api/v1/statuses/${id}/pin`
|
export const MASTODON_PIN_OWN_STATUS_URL = (id) => `/api/v1/statuses/${id}/pin`
|
||||||
const MASTODON_UNPIN_OWN_STATUS = (id) => `/api/v1/statuses/${id}/unpin`
|
export const MASTODON_UNPIN_OWN_STATUS_URL = (id) =>
|
||||||
const MASTODON_MUTE_CONVERSATION = (id) => `/api/v1/statuses/${id}/mute`
|
`/api/v1/statuses/${id}/unpin`
|
||||||
const MASTODON_UNMUTE_CONVERSATION = (id) => `/api/v1/statuses/${id}/unmute`
|
export const MASTODON_MUTE_CONVERSATION_URL = (id) =>
|
||||||
const MASTODON_DOMAIN_BLOCKS_URL = '/api/v1/domain_blocks'
|
`/api/v1/statuses/${id}/mute`
|
||||||
|
export const MASTODON_UNMUTE_CONVERSATION_URL = (id) =>
|
||||||
|
`/api/v1/statuses/${id}/unmute`
|
||||||
|
export const MASTODON_DOMAIN_BLOCKS_URL = '/api/v1/domain_blocks'
|
||||||
const MASTODON_ANNOUNCEMENTS_URL = '/api/v1/announcements'
|
const MASTODON_ANNOUNCEMENTS_URL = '/api/v1/announcements'
|
||||||
const MASTODON_ANNOUNCEMENTS_DISMISS_URL = (id) =>
|
const MASTODON_ANNOUNCEMENTS_DISMISS_URL = (id) =>
|
||||||
`/api/v1/announcements/${id}/dismiss`
|
`/api/v1/announcements/${id}/dismiss`
|
||||||
const PLEROMA_EMOJI_REACT_URL = (id, emoji) =>
|
export const PLEROMA_EMOJI_REACT_URL = (id, emoji) =>
|
||||||
`/api/v1/pleroma/statuses/${id}/reactions/${emoji}`
|
`/api/v1/pleroma/statuses/${id}/reactions/${emoji}`
|
||||||
const PLEROMA_EMOJI_UNREACT_URL = (id, emoji) =>
|
export const PLEROMA_EMOJI_UNREACT_URL = (id, emoji) =>
|
||||||
`/api/v1/pleroma/statuses/${id}/reactions/${emoji}`
|
`/api/v1/pleroma/statuses/${id}/reactions/${emoji}`
|
||||||
const PLEROMA_BACKUP_URL = '/api/v1/pleroma/backups'
|
const PLEROMA_BACKUP_URL = '/api/v1/pleroma/backups'
|
||||||
const PLEROMA_BOOKMARK_FOLDERS_URL = '/api/v1/pleroma/bookmark_folders'
|
const PLEROMA_BOOKMARK_FOLDERS_URL = '/api/v1/pleroma/bookmark_folders'
|
||||||
|
|
@ -143,39 +149,39 @@ export const bookmarkStatus = ({ id, credentials, ...options }) =>
|
||||||
payload: {
|
payload: {
|
||||||
folder_id: options.folder_id,
|
folder_id: options.folder_id,
|
||||||
},
|
},
|
||||||
})
|
}).then(({ data, ...rest }) => ({ ...rest, data: parseStatus(data) }))
|
||||||
|
|
||||||
export const unbookmarkStatus = ({ id, credentials }) =>
|
export const unbookmarkStatus = ({ id, credentials }) =>
|
||||||
promisedRequest({
|
promisedRequest({
|
||||||
url: MASTODON_UNBOOKMARK_STATUS_URL(id),
|
url: MASTODON_UNBOOKMARK_STATUS_URL(id),
|
||||||
credentials,
|
credentials,
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
})
|
}).then(({ data, ...rest }) => ({ ...rest, data: parseStatus(data) }))
|
||||||
|
|
||||||
export const pinOwnStatus = ({ id, credentials }) =>
|
export const pinOwnStatus = ({ id, credentials }) =>
|
||||||
promisedRequest({
|
promisedRequest({
|
||||||
url: MASTODON_PIN_OWN_STATUS(id),
|
url: MASTODON_PIN_OWN_STATUS_URL(id),
|
||||||
credentials,
|
credentials,
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
}).then(({ data, ...rest }) => ({ ...rest, data: parseStatus(data) }))
|
}).then(({ data, ...rest }) => ({ ...rest, data: parseStatus(data) }))
|
||||||
|
|
||||||
export const unpinOwnStatus = ({ id, credentials }) =>
|
export const unpinOwnStatus = ({ id, credentials }) =>
|
||||||
promisedRequest({
|
promisedRequest({
|
||||||
url: MASTODON_UNPIN_OWN_STATUS(id),
|
url: MASTODON_UNPIN_OWN_STATUS_URL(id),
|
||||||
credentials,
|
credentials,
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
}).then(({ data, ...rest }) => ({ ...rest, data: parseStatus(data) }))
|
}).then(({ data, ...rest }) => ({ ...rest, data: parseStatus(data) }))
|
||||||
|
|
||||||
export const muteConversation = ({ id, credentials }) =>
|
export const muteConversation = ({ id, credentials }) =>
|
||||||
promisedRequest({
|
promisedRequest({
|
||||||
url: MASTODON_MUTE_CONVERSATION(id),
|
url: MASTODON_MUTE_CONVERSATION_URL(id),
|
||||||
credentials,
|
credentials,
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
}).then(({ data, ...rest }) => ({ ...rest, data: parseStatus(data) }))
|
}).then(({ data, ...rest }) => ({ ...rest, data: parseStatus(data) }))
|
||||||
|
|
||||||
export const unmuteConversation = ({ id, credentials }) =>
|
export const unmuteConversation = ({ id, credentials }) =>
|
||||||
promisedRequest({
|
promisedRequest({
|
||||||
url: MASTODON_UNMUTE_CONVERSATION(id),
|
url: MASTODON_UNMUTE_CONVERSATION_URL(id),
|
||||||
credentials,
|
credentials,
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
}).then(({ data, ...rest }) => ({ ...rest, data: parseStatus(data) }))
|
}).then(({ data, ...rest }) => ({ ...rest, data: parseStatus(data) }))
|
||||||
|
|
@ -410,7 +416,6 @@ export const exportFriends = ({ id, credentials }) => {
|
||||||
id,
|
id,
|
||||||
maxId,
|
maxId,
|
||||||
credentials,
|
credentials,
|
||||||
withRelationships: true,
|
|
||||||
})
|
})
|
||||||
friends = [...friends, ...users]
|
friends = [...friends, ...users]
|
||||||
if (users.length === 0) {
|
if (users.length === 0) {
|
||||||
|
|
@ -657,7 +662,7 @@ export const fetchUserInLists = ({ id, credentials }) =>
|
||||||
|
|
||||||
export const removeUserFromFollowers = ({ id, credentials }) =>
|
export const removeUserFromFollowers = ({ id, credentials }) =>
|
||||||
promisedRequest({
|
promisedRequest({
|
||||||
url: MASTODON_REMOVE_USER_FROM_FOLLOWERS(id),
|
url: MASTODON_REMOVE_USER_FROM_FOLLOWERS_URL(id),
|
||||||
credentials,
|
credentials,
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -26,8 +26,26 @@ const PLEROMA_STREAMING_EVENTS = new Set([
|
||||||
'pleroma:respond',
|
'pleroma:respond',
|
||||||
])
|
])
|
||||||
|
|
||||||
|
export const WSConnectionStatus = Object.freeze({
|
||||||
|
JOINED: 1,
|
||||||
|
CLOSED: 2,
|
||||||
|
ERROR: 3,
|
||||||
|
DISABLED: 4,
|
||||||
|
STARTING: 5,
|
||||||
|
STARTING_INITIAL: 6,
|
||||||
|
})
|
||||||
|
|
||||||
|
export class WSEvent extends Event {
|
||||||
|
data
|
||||||
|
|
||||||
|
constructor(name, data, original) {
|
||||||
|
super(name)
|
||||||
|
this.data = data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// A thin wrapper around WebSocket API that allows adding a pre-processor to it
|
// A thin wrapper around WebSocket API that allows adding a pre-processor to it
|
||||||
// Uses EventTarget and a CustomEvent to proxy events
|
// Uses EventTarget and a WSEvent to proxy events
|
||||||
export const ProcessedWS = ({
|
export const ProcessedWS = ({
|
||||||
url,
|
url,
|
||||||
preprocessor = handleMastoWS,
|
preprocessor = handleMastoWS,
|
||||||
|
|
@ -39,9 +57,7 @@ export const ProcessedWS = ({
|
||||||
if (!socket) throw new Error(`Failed to create socket ${id}`)
|
if (!socket) throw new Error(`Failed to create socket ${id}`)
|
||||||
const proxy = (original, eventName, processor = (a) => a) => {
|
const proxy = (original, eventName, processor = (a) => a) => {
|
||||||
original.addEventListener(eventName, (eventData) => {
|
original.addEventListener(eventName, (eventData) => {
|
||||||
eventTarget.dispatchEvent(
|
eventTarget.dispatchEvent(new WSEvent(eventName, processor(eventData)))
|
||||||
new CustomEvent(eventName, { detail: processor(eventData) }),
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
socket.addEventListener('open', (wsEvent) => {
|
socket.addEventListener('open', (wsEvent) => {
|
||||||
|
|
@ -75,7 +91,7 @@ export const ProcessedWS = ({
|
||||||
/**/
|
/**/
|
||||||
|
|
||||||
const onAuthenticated = () => {
|
const onAuthenticated = () => {
|
||||||
eventTarget.dispatchEvent(new CustomEvent('pleroma:authenticated'))
|
eventTarget.dispatchEvent(new WSEvent('pleroma:authenticated'))
|
||||||
}
|
}
|
||||||
|
|
||||||
proxy(socket, 'open')
|
proxy(socket, 'open')
|
||||||
|
|
@ -126,14 +142,14 @@ export const handleMastoWS = (
|
||||||
const { data } = wsEvent
|
const { data } = wsEvent
|
||||||
if (!data) return
|
if (!data) return
|
||||||
const parsedEvent = JSON.parse(data)
|
const parsedEvent = JSON.parse(data)
|
||||||
const { event, payload } = parsedEvent
|
const { event, stream, payload } = parsedEvent
|
||||||
if (
|
if (
|
||||||
MASTODON_STREAMING_EVENTS.has(event) ||
|
MASTODON_STREAMING_EVENTS.has(event) ||
|
||||||
PLEROMA_STREAMING_EVENTS.has(event)
|
PLEROMA_STREAMING_EVENTS.has(event)
|
||||||
) {
|
) {
|
||||||
// MastoBE and PleromaBE both send payload for delete as a PLAIN string
|
// MastoBE and PleromaBE both send payload for delete as a PLAIN string
|
||||||
if (event === 'delete') {
|
if (event === 'delete') {
|
||||||
return { event, id: payload }
|
return { event, stream, id: payload }
|
||||||
}
|
}
|
||||||
const data = payload ? JSON.parse(payload) : null
|
const data = payload ? JSON.parse(payload) : null
|
||||||
if (event === 'pleroma:respond') {
|
if (event === 'pleroma:respond') {
|
||||||
|
|
@ -150,25 +166,16 @@ export const handleMastoWS = (
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
} else if (event === 'update') {
|
} else if (event === 'update') {
|
||||||
return { event, status: parseStatus(data) }
|
return { event, stream, status: parseStatus(data) }
|
||||||
} else if (event === 'status.update') {
|
} else if (event === 'status.update') {
|
||||||
return { event, status: parseStatus(data) }
|
return { event, stream, status: parseStatus(data) }
|
||||||
} else if (event === 'notification') {
|
} else if (event === 'notification') {
|
||||||
return { event, notification: parseNotification(data) }
|
return { event, stream, notification: parseNotification(data) }
|
||||||
} else if (event === 'pleroma:chat_update') {
|
} else if (event === 'pleroma:chat_update') {
|
||||||
return { event, chatUpdate: parseChat(data) }
|
return { event, stream, chatUpdate: parseChat(data) }
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
console.warn('Unknown event', wsEvent)
|
console.warn('Unknown event', wsEvent)
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const WSConnectionStatus = Object.freeze({
|
|
||||||
JOINED: 1,
|
|
||||||
CLOSED: 2,
|
|
||||||
ERROR: 3,
|
|
||||||
DISABLED: 4,
|
|
||||||
STARTING: 5,
|
|
||||||
STARTING_INITIAL: 6,
|
|
||||||
})
|
|
||||||
|
|
|
||||||
|
|
@ -36,9 +36,12 @@ import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.j
|
||||||
import { useInterfaceStore } from 'src/stores/interface.js'
|
import { useInterfaceStore } from 'src/stores/interface.js'
|
||||||
import { useLocalConfigStore } from 'src/stores/local_config.js'
|
import { useLocalConfigStore } from 'src/stores/local_config.js'
|
||||||
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
||||||
|
import { useNotificationsStore } from 'src/stores/notifications.js'
|
||||||
import { useOAuthStore } from 'src/stores/oauth.js'
|
import { useOAuthStore } from 'src/stores/oauth.js'
|
||||||
|
import { useStatusesStore } from 'src/stores/statuses.js'
|
||||||
import { useSyncConfigStore } from 'src/stores/sync_config.js'
|
import { useSyncConfigStore } from 'src/stores/sync_config.js'
|
||||||
import { useUserHighlightStore } from 'src/stores/user_highlight.js'
|
import { useUserHighlightStore } from 'src/stores/user_highlight.js'
|
||||||
|
import { useUsersStore } from 'src/stores/users.js'
|
||||||
|
|
||||||
import VBodyScrollLock from 'src/directives/body_scroll_lock'
|
import VBodyScrollLock from 'src/directives/body_scroll_lock'
|
||||||
import {
|
import {
|
||||||
|
|
@ -454,7 +457,7 @@ const setConfig = async ({ store }) => {
|
||||||
const checkOAuthToken = async ({ store }) => {
|
const checkOAuthToken = async ({ store }) => {
|
||||||
const oauth = useOAuthStore()
|
const oauth = useOAuthStore()
|
||||||
if (oauth.userToken) {
|
if (oauth.userToken) {
|
||||||
return store.dispatch('loginUser', oauth.userToken)
|
return useUsersStore().loginUser(oauth.userToken)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -541,7 +544,7 @@ const afterStoreSetup = async ({ pinia, store, storageError, i18n }) => {
|
||||||
window.highlightConfig = useUserHighlightStore()
|
window.highlightConfig = useUserHighlightStore()
|
||||||
|
|
||||||
FaviconService.initFaviconService()
|
FaviconService.initFaviconService()
|
||||||
initServiceWorker(store)
|
initServiceWorker(useNotificationsStore())
|
||||||
|
|
||||||
window.addEventListener('focus', () => updateFocus())
|
window.addEventListener('focus', () => updateFocus())
|
||||||
|
|
||||||
|
|
@ -589,6 +592,10 @@ const afterStoreSetup = async ({ pinia, store, storageError, i18n }) => {
|
||||||
|
|
||||||
useI18nStore().setI18n(i18n)
|
useI18nStore().setI18n(i18n)
|
||||||
|
|
||||||
|
// Global WS handlers
|
||||||
|
useInterfaceStore().attachSocket()
|
||||||
|
useStatusesStore().attachSocket()
|
||||||
|
|
||||||
app.use(router)
|
app.use(router)
|
||||||
app.use(store)
|
app.use(store)
|
||||||
app.use(i18n)
|
app.use(i18n)
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,16 @@
|
||||||
import AuthForm from 'src/components/auth_form/auth_form.js'
|
import AuthForm from 'src/components/auth_form/auth_form.js'
|
||||||
import BookmarkTimeline from 'src/components/bookmark_timeline/bookmark_timeline.vue'
|
|
||||||
import BubbleTimeline from 'src/components/bubble_timeline/bubble_timeline.vue'
|
|
||||||
import ConversationPage from 'src/components/conversation-page/conversation-page.vue'
|
import ConversationPage from 'src/components/conversation-page/conversation-page.vue'
|
||||||
import DMs from 'src/components/dm_timeline/dm_timeline.vue'
|
|
||||||
import FriendsTimeline from 'src/components/friends_timeline/friends_timeline.vue'
|
|
||||||
import NavPanel from 'src/components/nav_panel/nav_panel.vue'
|
import NavPanel from 'src/components/nav_panel/nav_panel.vue'
|
||||||
import PublicAndExternalTimeline from 'src/components/public_and_external_timeline/public_and_external_timeline.vue'
|
|
||||||
import PublicTimeline from 'src/components/public_timeline/public_timeline.vue'
|
|
||||||
import QuotesTimeline from 'src/components/quotes_timeline/quotes_timeline.vue'
|
|
||||||
import RemoteUserResolver from 'src/components/remote_user_resolver/remote_user_resolver.vue'
|
import RemoteUserResolver from 'src/components/remote_user_resolver/remote_user_resolver.vue'
|
||||||
import TagTimeline from 'src/components/tag_timeline/tag_timeline.vue'
|
import Timeline from 'src/components/timeline/timeline.vue'
|
||||||
|
|
||||||
import { useInstanceStore } from 'src/stores/instance.js'
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
|
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
|
||||||
|
import { useUsersStore } from 'src/stores/users.js'
|
||||||
|
|
||||||
export default (store) => {
|
export default () => {
|
||||||
const validateAuthenticatedRoute = (to, from, next) => {
|
const validateAuthenticatedRoute = (to, from, next) => {
|
||||||
if (store.state.users.currentUser) {
|
if (useUsersStore().currentUser) {
|
||||||
next()
|
next()
|
||||||
} else {
|
} else {
|
||||||
next(
|
next(
|
||||||
|
|
@ -31,7 +25,7 @@ export default (store) => {
|
||||||
path: '/',
|
path: '/',
|
||||||
redirect: () => {
|
redirect: () => {
|
||||||
return (
|
return (
|
||||||
(store.state.users.currentUser
|
(useUsersStore().currentUser
|
||||||
? useInstanceStore().instanceIdentity.redirectRootLogin
|
? useInstanceStore().instanceIdentity.redirectRootLogin
|
||||||
: useInstanceStore().instanceIdentity.redirectRootNoLogin) ||
|
: useInstanceStore().instanceIdentity.redirectRootNoLogin) ||
|
||||||
'/main/all'
|
'/main/all'
|
||||||
|
|
@ -41,22 +35,52 @@ export default (store) => {
|
||||||
{
|
{
|
||||||
name: 'public-external-timeline',
|
name: 'public-external-timeline',
|
||||||
path: '/main/all',
|
path: '/main/all',
|
||||||
component: PublicAndExternalTimeline,
|
component: Timeline,
|
||||||
|
props: () => ({
|
||||||
|
timelineRef: { name: 'publicAndExternal' },
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'public-timeline',
|
name: 'public-timeline',
|
||||||
path: '/main/public',
|
path: '/main/public',
|
||||||
component: PublicTimeline,
|
component: Timeline,
|
||||||
|
props: () => ({
|
||||||
|
timelineRef: { name: 'public' },
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'friends',
|
name: 'friends',
|
||||||
path: '/main/friends',
|
path: '/main/friends',
|
||||||
component: FriendsTimeline,
|
component: Timeline,
|
||||||
beforeEnter: validateAuthenticatedRoute,
|
beforeEnter: validateAuthenticatedRoute,
|
||||||
|
props: () => ({
|
||||||
|
timelineRef: { name: 'friends' },
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'tag-timeline',
|
||||||
|
path: '/tag/:id',
|
||||||
|
component: Timeline,
|
||||||
|
props: (route) => ({
|
||||||
|
timelineRef: { name: 'tag', argument: route.params.id },
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'bookmarks',
|
||||||
|
path: '/bookmarks',
|
||||||
|
component: Timeline,
|
||||||
|
props: (route) => ({
|
||||||
|
timelineRef: { name: 'bookmarks', argument: null },
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'bubble',
|
||||||
|
path: '/bubble',
|
||||||
|
component: Timeline,
|
||||||
|
props: () => ({
|
||||||
|
timelineRef: { name: 'bubble' },
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
{ name: 'tag-timeline', path: '/tag/:tag', component: TagTimeline },
|
|
||||||
{ name: 'bookmarks', path: '/bookmarks', component: BookmarkTimeline },
|
|
||||||
{ name: 'bubble', path: '/bubble', component: BubbleTimeline },
|
|
||||||
{
|
{
|
||||||
name: 'conversation',
|
name: 'conversation',
|
||||||
path: '/notice/:id',
|
path: '/notice/:id',
|
||||||
|
|
@ -71,7 +95,14 @@ export default (store) => {
|
||||||
meta: { dontScroll: true },
|
meta: { dontScroll: true },
|
||||||
beforeEnter: validateAuthenticatedRoute,
|
beforeEnter: validateAuthenticatedRoute,
|
||||||
},
|
},
|
||||||
{ name: 'quotes', path: '/notice/:id/quotes', component: QuotesTimeline },
|
{
|
||||||
|
name: 'quotes',
|
||||||
|
path: '/notice/:id/quotes',
|
||||||
|
component: Timeline,
|
||||||
|
props: (route) => ({
|
||||||
|
timelineRef: { name: 'quotes', argument: route.params.id },
|
||||||
|
}),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'remote-user-profile-acct',
|
name: 'remote-user-profile-acct',
|
||||||
path: '/remote-users/:_(@)?:username([^/@]+)@:hostname([^/@]+)',
|
path: '/remote-users/:_(@)?:username([^/@]+)@:hostname([^/@]+)',
|
||||||
|
|
@ -104,8 +135,11 @@ export default (store) => {
|
||||||
{
|
{
|
||||||
name: 'dms',
|
name: 'dms',
|
||||||
path: '/users/:username/dms',
|
path: '/users/:username/dms',
|
||||||
component: DMs,
|
component: Timeline,
|
||||||
beforeEnter: validateAuthenticatedRoute,
|
beforeEnter: validateAuthenticatedRoute,
|
||||||
|
props: () => ({
|
||||||
|
timelineRef: { name: 'dms' },
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'registration',
|
name: 'registration',
|
||||||
|
|
@ -202,8 +236,10 @@ export default (store) => {
|
||||||
{
|
{
|
||||||
name: 'lists-timeline',
|
name: 'lists-timeline',
|
||||||
path: '/lists/:id',
|
path: '/lists/:id',
|
||||||
component: () =>
|
component: Timeline,
|
||||||
import('src/components/lists_timeline/lists_timeline.vue'),
|
props: (route) => ({
|
||||||
|
timelineRef: { name: 'list', argument: route.params.id },
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'lists-edit',
|
name: 'lists-edit',
|
||||||
|
|
@ -237,7 +273,10 @@ export default (store) => {
|
||||||
{
|
{
|
||||||
name: 'bookmark-folder',
|
name: 'bookmark-folder',
|
||||||
path: '/bookmarks/:id',
|
path: '/bookmarks/:id',
|
||||||
component: BookmarkTimeline,
|
component: Timeline,
|
||||||
|
props: (route) => ({
|
||||||
|
timelineRef: { name: 'bookmarks', argument: route.params.id },
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'bookmark-folder-edit',
|
name: 'bookmark-folder-edit',
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import UserListMenu from 'src/components/user_list_menu/user_list_menu.vue'
|
||||||
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
|
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
|
||||||
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
||||||
import { useReportsStore } from 'src/stores/reports'
|
import { useReportsStore } from 'src/stores/reports'
|
||||||
|
import { useUsersStore } from 'src/stores/users.js'
|
||||||
|
|
||||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||||
import { faEllipsisV } from '@fortawesome/free-solid-svg-icons'
|
import { faEllipsisV } from '@fortawesome/free-solid-svg-icons'
|
||||||
|
|
@ -47,10 +48,10 @@ const AccountActions = {
|
||||||
this.showingConfirmBlock = false
|
this.showingConfirmBlock = false
|
||||||
},
|
},
|
||||||
showRepeats() {
|
showRepeats() {
|
||||||
this.$store.dispatch('showReblogs', this.user.id)
|
useUsersStore().showReblogs(this.user.id)
|
||||||
},
|
},
|
||||||
hideRepeats() {
|
hideRepeats() {
|
||||||
this.$store.dispatch('hideReblogs', this.user.id)
|
useUsersStore().hideReblogs(this.user.id)
|
||||||
},
|
},
|
||||||
blockUser() {
|
blockUser() {
|
||||||
if (this.$refs.timedBlockDialog) {
|
if (this.$refs.timedBlockDialog) {
|
||||||
|
|
@ -64,11 +65,11 @@ const AccountActions = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
doBlockUser() {
|
doBlockUser() {
|
||||||
this.$store.dispatch('blockUser', { id: this.user.id })
|
useUsersStore().blockUser(this.user.id)
|
||||||
this.hideConfirmBlock()
|
this.hideConfirmBlock()
|
||||||
},
|
},
|
||||||
unblockUser() {
|
unblockUser() {
|
||||||
this.$store.dispatch('unblockUser', this.user.id)
|
useUsersStore().unblockUser(this.user.id)
|
||||||
},
|
},
|
||||||
removeUserFromFollowers() {
|
removeUserFromFollowers() {
|
||||||
if (!this.shouldConfirmRemoveUserFromFollowers) {
|
if (!this.shouldConfirmRemoveUserFromFollowers) {
|
||||||
|
|
@ -78,7 +79,7 @@ const AccountActions = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
doRemoveUserFromFollowers() {
|
doRemoveUserFromFollowers() {
|
||||||
this.$store.dispatch('removeUserFromFollowers', this.user.id)
|
useUsersStore().removeUserFromFollowers(this.user.id)
|
||||||
this.hideConfirmRemoveUserFromFollowers()
|
this.hideConfirmRemoveUserFromFollowers()
|
||||||
},
|
},
|
||||||
reportUser() {
|
reportUser() {
|
||||||
|
|
@ -88,7 +89,7 @@ const AccountActions = {
|
||||||
this.$router.push({
|
this.$router.push({
|
||||||
name: 'chat',
|
name: 'chat',
|
||||||
params: {
|
params: {
|
||||||
username: this.$store.state.users.currentUser.screen_name,
|
username: useUsersStore().currentUser.screen_name,
|
||||||
recipient_id: this.user.id,
|
recipient_id: this.user.id,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
import { mapState } from 'vuex'
|
import { mapState } from 'pinia'
|
||||||
|
|
||||||
import AnnouncementEditor from 'src/components/announcement_editor/announcement_editor.vue'
|
import AnnouncementEditor from 'src/components/announcement_editor/announcement_editor.vue'
|
||||||
import localeService from '../../services/locale/locale.service.js'
|
import localeService from '../../services/locale/locale.service.js'
|
||||||
|
|
||||||
import { useAnnouncementsStore } from 'src/stores/announcements.js'
|
import { useAnnouncementsStore } from 'src/stores/announcements.js'
|
||||||
|
import { useUsersStore } from 'src/stores/users.js'
|
||||||
|
|
||||||
const Announcement = {
|
const Announcement = {
|
||||||
components: {
|
components: {
|
||||||
|
|
@ -25,9 +26,7 @@ const Announcement = {
|
||||||
announcement: Object,
|
announcement: Object,
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState({
|
...mapState(useUsersStore, ['currentUser']),
|
||||||
currentUser: (state) => state.users.currentUser,
|
|
||||||
}),
|
|
||||||
canEditAnnouncement() {
|
canEditAnnouncement() {
|
||||||
return this.currentUser?.privileges.has(
|
return this.currentUser?.privileges.has(
|
||||||
'announcements_manage_announcements',
|
'announcements_manage_announcements',
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
import { mapState } from 'vuex'
|
import { mapState } from 'pinia'
|
||||||
|
|
||||||
import Announcement from 'src/components/announcement/announcement.vue'
|
import Announcement from 'src/components/announcement/announcement.vue'
|
||||||
import AnnouncementEditor from 'src/components/announcement_editor/announcement_editor.vue'
|
import AnnouncementEditor from 'src/components/announcement_editor/announcement_editor.vue'
|
||||||
|
|
||||||
import { useAnnouncementsStore } from 'src/stores/announcements.js'
|
import { useAnnouncementsStore } from 'src/stores/announcements.js'
|
||||||
|
import { useUsersStore } from 'src/stores/users.js'
|
||||||
|
|
||||||
const AnnouncementsPage = {
|
const AnnouncementsPage = {
|
||||||
components: {
|
components: {
|
||||||
|
|
@ -26,9 +27,7 @@ const AnnouncementsPage = {
|
||||||
useAnnouncementsStore().fetchAnnouncements()
|
useAnnouncementsStore().fetchAnnouncements()
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState({
|
...mapState(useUsersStore, ['currentUser']),
|
||||||
currentUser: (state) => state.users.currentUser,
|
|
||||||
}),
|
|
||||||
announcements() {
|
announcements() {
|
||||||
return useAnnouncementsStore().announcements
|
return useAnnouncementsStore().announcements
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
class="avatars-item"
|
class="avatars-item"
|
||||||
>
|
>
|
||||||
<UserAvatar
|
<UserAvatar
|
||||||
:user="user"
|
:user-id="user.id"
|
||||||
class="avatar-small"
|
class="avatar-small"
|
||||||
/>
|
/>
|
||||||
</router-link>
|
</router-link>
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
>
|
>
|
||||||
<UserAvatar
|
<UserAvatar
|
||||||
class="user-avatar avatar"
|
class="user-avatar avatar"
|
||||||
:user="user"
|
:user-id="user.id"
|
||||||
@click.prevent
|
@click.prevent
|
||||||
/>
|
/>
|
||||||
</UserPopover>
|
</UserPopover>
|
||||||
|
|
|
||||||
|
|
@ -4,15 +4,16 @@ import BasicUserCard from 'src/components/basic_user_card/basic_user_card.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 { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
|
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
|
||||||
|
import { useUsersStore } from 'src/stores/users.js'
|
||||||
|
|
||||||
const BlockCard = {
|
const BlockCard = {
|
||||||
props: ['userId'],
|
props: ['userId'],
|
||||||
computed: {
|
computed: {
|
||||||
user() {
|
user() {
|
||||||
return this.$store.getters.findUser(this.userId)
|
return useUsersStore().findUser(this.userId)
|
||||||
},
|
},
|
||||||
relationship() {
|
relationship() {
|
||||||
return this.$store.getters.relationship(this.userId)
|
return useUsersStore().relationship(this.userId)
|
||||||
},
|
},
|
||||||
blocked() {
|
blocked() {
|
||||||
return this.relationship.blocking
|
return this.relationship.blocking
|
||||||
|
|
@ -35,13 +36,13 @@ const BlockCard = {
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
unblockUser() {
|
unblockUser() {
|
||||||
this.$store.dispatch('unblockUser', this.user.id)
|
useUsersStore().unblockUser(this.user.id)
|
||||||
},
|
},
|
||||||
blockUser() {
|
blockUser() {
|
||||||
if (this.blockExpiration) {
|
if (this.blockExpiration) {
|
||||||
this.$refs.timedBlockDialog.optionallyPrompt()
|
this.$refs.timedBlockDialog.optionallyPrompt()
|
||||||
} else {
|
} else {
|
||||||
this.$store.dispatch('blockUser', { id: this.user.id })
|
useUsersStore().blockUser(this.user.id)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,38 +0,0 @@
|
||||||
import Timeline from 'src/components/timeline/timeline.vue'
|
|
||||||
|
|
||||||
const Bookmarks = {
|
|
||||||
created() {
|
|
||||||
this.$store.commit('clearTimeline', { timeline: 'bookmarks' })
|
|
||||||
this.$store.dispatch('startFetchingTimeline', {
|
|
||||||
timeline: 'bookmarks',
|
|
||||||
bookmarkFolderId: this.folderId || null,
|
|
||||||
})
|
|
||||||
},
|
|
||||||
components: {
|
|
||||||
Timeline,
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
folderId() {
|
|
||||||
return this.$route.params.id
|
|
||||||
},
|
|
||||||
timeline() {
|
|
||||||
return this.$store.state.statuses.timelines.bookmarks
|
|
||||||
},
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
folderId() {
|
|
||||||
this.$store.commit('clearTimeline', { timeline: 'bookmarks' })
|
|
||||||
this.$store.dispatch('stopFetchingTimeline', 'bookmarks')
|
|
||||||
this.$store.dispatch('startFetchingTimeline', {
|
|
||||||
timeline: 'bookmarks',
|
|
||||||
bookmarkFolderId: this.folderId || null,
|
|
||||||
})
|
|
||||||
},
|
|
||||||
},
|
|
||||||
unmounted() {
|
|
||||||
this.$store.commit('clearTimeline', { timeline: 'bookmarks' })
|
|
||||||
this.$store.dispatch('stopFetchingTimeline', 'bookmarks')
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Bookmarks
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
<template>
|
|
||||||
<Timeline
|
|
||||||
:title="$t('nav.bookmarks')"
|
|
||||||
:timeline="timeline"
|
|
||||||
:timeline-name="'bookmarks'"
|
|
||||||
:bookmark-folder-id="folderId"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script src="./bookmark_timeline.js"></script>
|
|
||||||
|
|
@ -1,20 +0,0 @@
|
||||||
import Timeline from 'src/components/timeline/timeline.vue'
|
|
||||||
|
|
||||||
const BubbleTimeline = {
|
|
||||||
components: {
|
|
||||||
Timeline,
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
timeline() {
|
|
||||||
return this.$store.state.statuses.timelines.bubble
|
|
||||||
},
|
|
||||||
},
|
|
||||||
created() {
|
|
||||||
this.$store.dispatch('startFetchingTimeline', { timeline: 'bubble' })
|
|
||||||
},
|
|
||||||
unmounted() {
|
|
||||||
this.$store.dispatch('stopFetchingTimeline', 'bubble')
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
export default BubbleTimeline
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
<template>
|
|
||||||
<Timeline
|
|
||||||
:title="$t('nav.bubble')"
|
|
||||||
:timeline="timeline"
|
|
||||||
:timeline-name="'bubble'"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script src="./bubble_timeline.js"></script>
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
import { mapState as mapPiniaState } from 'pinia'
|
import { mapState } from 'pinia'
|
||||||
import { mapState } from 'vuex'
|
|
||||||
|
|
||||||
import ChatListItem from 'src/components/chat_list_item/chat_list_item.vue'
|
import ChatListItem from 'src/components/chat_list_item/chat_list_item.vue'
|
||||||
import ChatNew from 'src/components/chat_new/chat_new.vue'
|
import ChatNew from 'src/components/chat_new/chat_new.vue'
|
||||||
import List from 'src/components/list/list.vue'
|
import List from 'src/components/list/list.vue'
|
||||||
|
|
||||||
import { useChatsStore } from 'src/stores/chats.js'
|
import { useChatsStore } from 'src/stores/chats.js'
|
||||||
|
import { useUsersStore } from 'src/stores/users.js'
|
||||||
|
|
||||||
const ChatList = {
|
const ChatList = {
|
||||||
components: {
|
components: {
|
||||||
|
|
@ -14,10 +14,8 @@ const ChatList = {
|
||||||
ChatNew,
|
ChatNew,
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState({
|
...mapState(useUsersStore, ['currentUser']),
|
||||||
currentUser: (state) => state.users.currentUser,
|
...mapState(useChatsStore, ['sortedChatList']),
|
||||||
}),
|
|
||||||
...mapPiniaState(useChatsStore, ['sortedChatList']),
|
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { mapState } from 'vuex'
|
import { mapState } from 'pinia'
|
||||||
|
|
||||||
import AvatarList from 'src/components/avatar_list/avatar_list.vue'
|
import AvatarList from 'src/components/avatar_list/avatar_list.vue'
|
||||||
import ChatTitle from 'src/components/chat_title/chat_title.vue'
|
import ChatTitle from 'src/components/chat_title/chat_title.vue'
|
||||||
|
|
@ -6,6 +6,8 @@ import StatusBody from 'src/components/status_content/status_content.vue'
|
||||||
import Timeago from 'src/components/timeago/timeago.vue'
|
import Timeago from 'src/components/timeago/timeago.vue'
|
||||||
import UserAvatar from 'src/components/user_avatar/user_avatar.vue'
|
import UserAvatar from 'src/components/user_avatar/user_avatar.vue'
|
||||||
|
|
||||||
|
import { useUsersStore } from 'src/stores/users.js'
|
||||||
|
|
||||||
const ChatListItem = {
|
const ChatListItem = {
|
||||||
name: 'ChatListItem',
|
name: 'ChatListItem',
|
||||||
props: ['chat'],
|
props: ['chat'],
|
||||||
|
|
@ -17,9 +19,7 @@ const ChatListItem = {
|
||||||
StatusBody,
|
StatusBody,
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState({
|
...mapState(useUsersStore, ['currentUser']),
|
||||||
currentUser: (state) => state.users.currentUser,
|
|
||||||
}),
|
|
||||||
attachmentInfo() {
|
attachmentInfo() {
|
||||||
if (this.chat.lastMessage.attachments.length === 0) {
|
if (this.chat.lastMessage.attachments.length === 0) {
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
>
|
>
|
||||||
<div class="chat-list-item-left">
|
<div class="chat-list-item-left">
|
||||||
<UserAvatar
|
<UserAvatar
|
||||||
:user="chat.account"
|
:user-id="chat.account.id"
|
||||||
height="48px"
|
height="48px"
|
||||||
width="48px"
|
width="48px"
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
import { mapState as mapPiniaState } from 'pinia'
|
import { mapState } from 'pinia'
|
||||||
import { defineAsyncComponent } from 'vue'
|
import { defineAsyncComponent } from 'vue'
|
||||||
import { mapState } from 'vuex'
|
|
||||||
|
|
||||||
import Attachment from 'src/components/attachment/attachment.vue'
|
import Attachment from 'src/components/attachment/attachment.vue'
|
||||||
import ChatMessageDate from 'src/components/chat_message_date/chat_message_date.vue'
|
import ChatMessageDate from 'src/components/chat_message_date/chat_message_date.vue'
|
||||||
|
|
@ -20,6 +19,8 @@ import UserPopover from 'src/components/user_popover/user_popover.vue'
|
||||||
import { useInstanceStore } from 'src/stores/instance.js'
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import { useInterfaceStore } from 'src/stores/interface'
|
import { useInterfaceStore } from 'src/stores/interface'
|
||||||
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
||||||
|
import { useStatusesStore } from 'src/stores/statuses.js'
|
||||||
|
import { useUsersStore } from 'src/stores/users.js'
|
||||||
|
|
||||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||||
import {
|
import {
|
||||||
|
|
@ -79,7 +80,7 @@ const ChatMessage = {
|
||||||
return this.isStatus ? this.message.user.id : this.message.account_id
|
return this.isStatus ? this.message.user.id : this.message.account_id
|
||||||
},
|
},
|
||||||
author() {
|
author() {
|
||||||
return this.$store.getters.findUser(this.authorId)
|
return useUsersStore().findUser(this.authorId)
|
||||||
},
|
},
|
||||||
isCurrentUser() {
|
isCurrentUser() {
|
||||||
// mini-hack/optimizaiton:
|
// mini-hack/optimizaiton:
|
||||||
|
|
@ -100,25 +101,21 @@ const ChatMessage = {
|
||||||
return !this.message.in_reply_to_status_id
|
return !this.message.in_reply_to_status_id
|
||||||
},
|
},
|
||||||
customReplyTo() {
|
customReplyTo() {
|
||||||
return this.$store.state.statuses.allStatusesObject[
|
return useStatusesStore().allStatuses.get(
|
||||||
this.message.in_reply_to_status_id
|
this.message.in_reply_to_status_id,
|
||||||
]
|
)
|
||||||
},
|
},
|
||||||
replyToName() {
|
replyToName() {
|
||||||
if (this.message.in_reply_to_screen_name) {
|
if (this.message.in_reply_to_screen_name) {
|
||||||
return this.message.in_reply_to_screen_name
|
return this.message.in_reply_to_screen_name
|
||||||
} else {
|
} else {
|
||||||
const user = this.$store.getters.findUser(
|
const user = useUsersStore().findUser(this.message.in_reply_to_user_id)
|
||||||
this.message.in_reply_to_user_id,
|
|
||||||
)
|
|
||||||
return user?.screen_name_ui
|
return user?.screen_name_ui
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
replyProfileLink() {
|
replyProfileLink() {
|
||||||
if (this.isCustomReply) {
|
if (this.isCustomReply) {
|
||||||
const user = this.$store.getters.findUser(
|
const user = useUsersStore().findUser(this.message.in_reply_to_user_id)
|
||||||
this.message.in_reply_to_user_id,
|
|
||||||
)
|
|
||||||
// FIXME Why user not found sometimes???
|
// FIXME Why user not found sometimes???
|
||||||
return user ? user.statusnet_profile_url : 'NOT_FOUND'
|
return user ? user.statusnet_profile_url : 'NOT_FOUND'
|
||||||
}
|
}
|
||||||
|
|
@ -167,14 +164,12 @@ const ChatMessage = {
|
||||||
},
|
},
|
||||||
|
|
||||||
// Global stuff
|
// Global stuff
|
||||||
...mapPiniaState(useInterfaceStore, {
|
...mapState(useInterfaceStore, {
|
||||||
betterShadow: (store) => store.browserSupport.cssFilter,
|
betterShadow: (store) => store.browserSupport.cssFilter,
|
||||||
}),
|
}),
|
||||||
...mapState({
|
...mapState(useUsersStore, ['currentUser']),
|
||||||
currentUser: (state) => state.users.currentUser,
|
...mapState(useInstanceStore, ['restrictedNicknames']),
|
||||||
restrictedNicknames: (state) => useInstanceStore().restrictedNicknames,
|
...mapState(useMergedConfigStore, ['mergedConfig']),
|
||||||
}),
|
|
||||||
...mapPiniaState(useMergedConfigStore, ['mergedConfig']),
|
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,7 @@
|
||||||
<UserAvatar
|
<UserAvatar
|
||||||
v-if="author"
|
v-if="author"
|
||||||
:compact="true"
|
:compact="true"
|
||||||
:user="author"
|
:user-id="author.id"
|
||||||
/>
|
/>
|
||||||
</UserPopover>
|
</UserPopover>
|
||||||
<div
|
<div
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
import { mapGetters, mapState } from 'vuex'
|
import { mapState } from 'pinia'
|
||||||
|
|
||||||
import BasicUserCard from 'src/components/basic_user_card/basic_user_card.vue'
|
import BasicUserCard from 'src/components/basic_user_card/basic_user_card.vue'
|
||||||
import UserAvatar from 'src/components/user_avatar/user_avatar.vue'
|
import UserAvatar from 'src/components/user_avatar/user_avatar.vue'
|
||||||
|
|
||||||
import { useOAuthStore } from 'src/stores/oauth.js'
|
import { useOAuthStore } from 'src/stores/oauth.js'
|
||||||
|
import { useUsersStore } from 'src/stores/users.js'
|
||||||
|
|
||||||
import { chats } from 'src/api/chats.js'
|
import { chats } from 'src/api/chats.js'
|
||||||
|
|
||||||
|
|
@ -42,10 +43,7 @@ const chatNew = {
|
||||||
return this.suggestions
|
return this.suggestions
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
...mapState({
|
...mapState(useUsersStore, ['currentUser', 'findUser']),
|
||||||
currentUser: (state) => state.users.currentUser,
|
|
||||||
}),
|
|
||||||
...mapGetters(['findUser']),
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
goBack() {
|
goBack() {
|
||||||
|
|
@ -73,7 +71,8 @@ const chatNew = {
|
||||||
this.loading = true
|
this.loading = true
|
||||||
this.userIds = []
|
this.userIds = []
|
||||||
this.$store
|
this.$store
|
||||||
.dispatch('search', { q: query, resolve: true, type: 'accounts' })
|
this.useSearchStore()
|
||||||
|
.search({ q: query, resolve: true, type: 'accounts' })
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
this.loading = false
|
this.loading = false
|
||||||
this.userIds = data.accounts.map((a) => a.id)
|
this.userIds = data.accounts.map((a) => a.id)
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@
|
||||||
>
|
>
|
||||||
<UserAvatar
|
<UserAvatar
|
||||||
class="titlebar-avatar"
|
class="titlebar-avatar"
|
||||||
:user="user"
|
:user-id="user.id"
|
||||||
/>
|
/>
|
||||||
</UserPopover>
|
</UserPopover>
|
||||||
<RichContent
|
<RichContent
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
import { get, maxBy, minBy, sortBy, throttle } from 'lodash'
|
import { get, maxBy, minBy, sortBy, throttle } from 'lodash'
|
||||||
import { mapState as mapPiniaState } from 'pinia'
|
import { mapState } from 'pinia'
|
||||||
import { nextTick } from 'vue'
|
import { nextTick } from 'vue'
|
||||||
import { mapState } from 'vuex'
|
|
||||||
|
|
||||||
import ChatMessageList from 'src/components/chat_message_list/chat_message_list.vue'
|
import ChatMessageList from 'src/components/chat_message_list/chat_message_list.vue'
|
||||||
import ChatTitle from 'src/components/chat_title/chat_title.vue'
|
import ChatTitle from 'src/components/chat_title/chat_title.vue'
|
||||||
|
|
@ -19,6 +18,9 @@ import { useChatsStore } from 'src/stores/chats.js'
|
||||||
import { useInterfaceStore } from 'src/stores/interface.js'
|
import { useInterfaceStore } from 'src/stores/interface.js'
|
||||||
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
||||||
import { useOAuthStore } from 'src/stores/oauth.js'
|
import { useOAuthStore } from 'src/stores/oauth.js'
|
||||||
|
import { useStatusesStore } from 'src/stores/statuses.js'
|
||||||
|
import { useStreamingStore } from 'src/stores/streaming.js'
|
||||||
|
import { useUsersStore } from 'src/stores/users.js'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
chatMessages,
|
chatMessages,
|
||||||
|
|
@ -85,6 +87,8 @@ const Chat = {
|
||||||
|
|
||||||
// Internal network stuff
|
// Internal network stuff
|
||||||
fetcher: null,
|
fetcher: null,
|
||||||
|
socket: null,
|
||||||
|
streaming: false,
|
||||||
errorLoadingChat: false,
|
errorLoadingChat: false,
|
||||||
messageRetriers: {},
|
messageRetriers: {},
|
||||||
idempotencyKeyIndex: {},
|
idempotencyKeyIndex: {},
|
||||||
|
|
@ -92,7 +96,8 @@ const Chat = {
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
if (this.testMode) return
|
if (this.testMode) return
|
||||||
this.startFetching()
|
this.activate()
|
||||||
|
this.attachSocket()
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
window.addEventListener('resize', this.handleResize)
|
window.addEventListener('resize', this.handleResize)
|
||||||
|
|
@ -118,10 +123,13 @@ const Chat = {
|
||||||
this.handleVisibilityChange,
|
this.handleVisibilityChange,
|
||||||
false,
|
false,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (this.testMode) return
|
||||||
|
this.deactivate()
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
conversationId() {
|
conversationId() {
|
||||||
const status = this.$store.state.statuses.allStatusesObject[this.statusId]
|
const status = useStatusesStore().allStatuses.get(this.statusId)
|
||||||
return get(
|
return get(
|
||||||
status,
|
status,
|
||||||
'retweeted_status.statusnet_conversation_id',
|
'retweeted_status.statusnet_conversation_id',
|
||||||
|
|
@ -157,17 +165,14 @@ const Chat = {
|
||||||
if (this.isConversation) return false // Unsupported
|
if (this.isConversation) return false // Unsupported
|
||||||
return (
|
return (
|
||||||
this.mergedConfig.useStreamingApi &&
|
this.mergedConfig.useStreamingApi &&
|
||||||
this.mastoUserSocketStatus === WSConnectionStatus.JOINED
|
useStreamingStore().state === WSConnectionStatus.JOINED
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
...mapPiniaState(useInterfaceStore, {
|
...mapState(useInterfaceStore, {
|
||||||
mobileLayout: (store) => store.layoutType === 'mobile',
|
mobileLayout: (store) => store.layoutType === 'mobile',
|
||||||
}),
|
}),
|
||||||
...mapPiniaState(useMergedConfigStore, ['mergedConfig']),
|
...mapState(useMergedConfigStore, ['mergedConfig']),
|
||||||
...mapState({
|
...mapState(useUsersStore, ['currentUser']),
|
||||||
mastoUserSocketStatus: (state) => state.api.mastoUserSocketStatus,
|
|
||||||
currentUser: (state) => state.users.currentUser,
|
|
||||||
}),
|
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
messages(old, neu) {
|
messages(old, neu) {
|
||||||
|
|
@ -226,16 +231,85 @@ const Chat = {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
this.clear()
|
this.deactivate()
|
||||||
this.startFetching()
|
this.activate()
|
||||||
},
|
|
||||||
mastoUserSocketStatus(newValue) {
|
|
||||||
if (newValue === WSConnectionStatus.JOINED) {
|
|
||||||
this.fetchChat({ isFirstFetch: true })
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
async activate() {
|
||||||
|
if (!this.isConversation) {
|
||||||
|
try {
|
||||||
|
const result = await getOrCreateChat({
|
||||||
|
accountId: this.chatUserId,
|
||||||
|
credentials: useOAuthStore().token,
|
||||||
|
})
|
||||||
|
useUsersStore().addNewUsers(result)
|
||||||
|
const { data } = result
|
||||||
|
data.account = useUsersStore().findUser(data.account.id)
|
||||||
|
this.chat = data
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Error creating or getting a chat', e)
|
||||||
|
this.errorLoadingChat = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.isConversation || this.chat) {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.scrollDown({ forceRead: true })
|
||||||
|
})
|
||||||
|
this.startFetching('Chat activated', true)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
deactivate() {
|
||||||
|
this.clear()
|
||||||
|
if (!this.streaming) {
|
||||||
|
this.stopFetching()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
attachSocket() {
|
||||||
|
const et = new EventTarget()
|
||||||
|
const socket = { et }
|
||||||
|
|
||||||
|
et.addEventListener('update', this.onStreamMessage)
|
||||||
|
et.addEventListener('open', this.onStreamConnect)
|
||||||
|
et.addEventListener('close', this.onStreamDisconnect)
|
||||||
|
|
||||||
|
useStreamingStore().addSubscriber(socket)
|
||||||
|
this.socket = socket
|
||||||
|
},
|
||||||
|
detachSocket() {
|
||||||
|
const { et } = this.socket
|
||||||
|
|
||||||
|
et.removeEventListener('update', this.onStreamMessage)
|
||||||
|
et.removeEventListener('open', this.onStreamConnect)
|
||||||
|
et.removeEventListener('close', this.onStreamDisconnect)
|
||||||
|
|
||||||
|
useStreamingStore().removeSubscriber(this.socket)
|
||||||
|
},
|
||||||
|
|
||||||
|
// Poll & Push
|
||||||
|
onStreamConnect() {
|
||||||
|
this.streaming = true
|
||||||
|
this.stopFetching('Socket connected')
|
||||||
|
},
|
||||||
|
onStreamDisconnect(closeEvent) {
|
||||||
|
this.streaming = false
|
||||||
|
this.startFetching('Socket disconnected')
|
||||||
|
},
|
||||||
|
startFetching(reason, isFirstFetch) {
|
||||||
|
console.debug('[Chat View] Started fetching', 'Reason:', reason)
|
||||||
|
this.fetcher = promiseInterval(
|
||||||
|
() => this.fetchChat({ fetchLatest: true }),
|
||||||
|
5000,
|
||||||
|
)
|
||||||
|
this.fetchChat({ isFirstFetch })
|
||||||
|
},
|
||||||
|
stopFetching(reason) {
|
||||||
|
console.debug('[Chat View] Stopped fetching', 'Reason:', reason)
|
||||||
|
this.fetcher.stop()
|
||||||
|
this.fetcher = null
|
||||||
|
},
|
||||||
|
|
||||||
// Actions
|
// Actions
|
||||||
async readChat() {
|
async readChat() {
|
||||||
if (this.conversationId) return // Unsupported
|
if (this.conversationId) return // Unsupported
|
||||||
|
|
@ -259,18 +333,8 @@ const Chat = {
|
||||||
this.lastReadMessageId = this.maxId
|
this.lastReadMessageId = this.maxId
|
||||||
this.newMessageCount = 0
|
this.newMessageCount = 0
|
||||||
},
|
},
|
||||||
scrollDown(options = {}) {
|
|
||||||
const { behavior = 'auto', forceRead = false } = options
|
// Clears
|
||||||
this.$nextTick(() => {
|
|
||||||
window.scrollTo({
|
|
||||||
top: document.documentElement.scrollHeight,
|
|
||||||
behavior,
|
|
||||||
})
|
|
||||||
})
|
|
||||||
if (forceRead) {
|
|
||||||
this.readChat()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
cullOlder() {
|
cullOlder() {
|
||||||
const maxIndex = this.messages.length
|
const maxIndex = this.messages.length
|
||||||
const minIndex = maxIndex - 50
|
const minIndex = maxIndex - 50
|
||||||
|
|
@ -366,35 +430,12 @@ const Chat = {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async startFetching() {
|
onStreamMessage({ data }) {
|
||||||
if (!this.isConversation) {
|
const messages = data.filter(
|
||||||
try {
|
({ statusnet_conversation_id }) =>
|
||||||
const { data } = await getOrCreateChat({
|
statusnet_conversation_id === this.conversationId,
|
||||||
accountId: this.chatUserId,
|
|
||||||
credentials: useOAuthStore().token,
|
|
||||||
})
|
|
||||||
this.$store.commit('addNewUsers', [data.account])
|
|
||||||
data.account = this.$store.getters.findUser(data.account.id)
|
|
||||||
this.chat = data
|
|
||||||
} catch (e) {
|
|
||||||
console.error('Error creating or getting a chat', e)
|
|
||||||
this.errorLoadingChat = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.isConversation || this.chat) {
|
|
||||||
this.$nextTick(() => {
|
|
||||||
this.scrollDown({ forceRead: true })
|
|
||||||
})
|
|
||||||
this.doStartFetching()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
doStartFetching() {
|
|
||||||
this.fetcher = promiseInterval(
|
|
||||||
() => this.fetchChat({ fetchLatest: true }),
|
|
||||||
5000,
|
|
||||||
)
|
)
|
||||||
this.fetchChat({ isFirstFetch: true })
|
this.addMessages({ messages })
|
||||||
},
|
},
|
||||||
addMessages({ messages: newMessages }) {
|
addMessages({ messages: newMessages }) {
|
||||||
for (let i = 0; i < newMessages.length; i++) {
|
for (let i = 0; i < newMessages.length; i++) {
|
||||||
|
|
@ -438,9 +479,6 @@ const Chat = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
goBack() {
|
|
||||||
this.$router.back()
|
|
||||||
},
|
|
||||||
|
|
||||||
// Optimistic posting (chats only)
|
// Optimistic posting (chats only)
|
||||||
async sendMessage({ status, media, idempotencyKey }) {
|
async sendMessage({ status, media, idempotencyKey }) {
|
||||||
|
|
@ -538,11 +576,14 @@ const Chat = {
|
||||||
|
|
||||||
// Event handlers
|
// Event handlers
|
||||||
onPosted(data) {
|
onPosted(data) {
|
||||||
this.explicitReplyStatus = null
|
// only conversation poster has the returned data
|
||||||
this.$router.push({
|
if (this.isConversation) {
|
||||||
name: 'conversation2',
|
this.explicitReplyStatus = null
|
||||||
params: { statusId: data.id },
|
this.$router.push({
|
||||||
})
|
name: 'conversation2',
|
||||||
|
params: { statusId: data.id },
|
||||||
|
})
|
||||||
|
}
|
||||||
},
|
},
|
||||||
handleVisibilityChange() {
|
handleVisibilityChange() {
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
|
|
@ -618,6 +659,23 @@ const Chat = {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Misc
|
||||||
|
scrollDown(options = {}) {
|
||||||
|
const { behavior = 'auto', forceRead = false } = options
|
||||||
|
this.$nextTick(() => {
|
||||||
|
window.scrollTo({
|
||||||
|
top: document.documentElement.scrollHeight,
|
||||||
|
behavior,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
if (forceRead) {
|
||||||
|
this.readChat()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
goBack() {
|
||||||
|
this.$router.back()
|
||||||
|
},
|
||||||
|
|
||||||
// Ugly
|
// Ugly
|
||||||
// TODO move to ChatMessage
|
// TODO move to ChatMessage
|
||||||
async deleteChatMessage({ chatId, messageId }) {
|
async deleteChatMessage({ chatId, messageId }) {
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@ import { defineAsyncComponent } from 'vue'
|
||||||
import Select from 'src/components/select/select.vue'
|
import Select from 'src/components/select/select.vue'
|
||||||
|
|
||||||
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
||||||
|
import { useStatusesStore } from 'src/stores/statuses.js'
|
||||||
|
import { useUsersStore } from 'src/stores/users.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: ['type', 'user', 'status'],
|
props: ['type', 'user', 'status'],
|
||||||
|
|
@ -33,9 +35,7 @@ export default {
|
||||||
return this.status.conversation_muted
|
return this.status.conversation_muted
|
||||||
},
|
},
|
||||||
domainIsMuted() {
|
domainIsMuted() {
|
||||||
return new Set(this.$store.state.users.currentUser.domainMutes).has(
|
return new Set(useUsersStore().currentUser.domainMutes).has(this.domain)
|
||||||
this.domain,
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
shouldConfirm() {
|
shouldConfirm() {
|
||||||
switch (this.type) {
|
switch (this.type) {
|
||||||
|
|
@ -70,17 +70,17 @@ export default {
|
||||||
switch (this.type) {
|
switch (this.type) {
|
||||||
case 'domain': {
|
case 'domain': {
|
||||||
if (!this.domainIsMuted) {
|
if (!this.domainIsMuted) {
|
||||||
this.$store.dispatch('muteDomain', this.domain)
|
useUsersStore().muteDomain(this.domain)
|
||||||
} else {
|
} else {
|
||||||
this.$store.dispatch('unmuteDomain', this.domain)
|
useUsersStore().unmuteDomain(this.domain)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case 'conversation': {
|
case 'conversation': {
|
||||||
if (!this.conversationIsMuted) {
|
if (!this.conversationIsMuted) {
|
||||||
this.$store.dispatch('muteConversation', { id: this.status.id })
|
useStatusesStore().muteConversation(this.status.id)
|
||||||
} else {
|
} else {
|
||||||
this.$store.dispatch('unmuteConversation', { id: this.status.id })
|
useStatusesStore().unmuteConversation(this.status.id)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { clone, filter, findIndex, get, reduce } from 'lodash'
|
import { get, reduce } from 'lodash'
|
||||||
import { mapState as mapPiniaState } from 'pinia'
|
import { mapState as mapPiniaState } from 'pinia'
|
||||||
import { mapState } from 'vuex'
|
import { mapState } from 'vuex'
|
||||||
|
|
||||||
|
|
@ -9,9 +9,10 @@ import QuickViewSettings from 'src/components/quick_view_settings/quick_view_set
|
||||||
import RichContent from 'src/components/rich_content/rich_content.jsx'
|
import RichContent from 'src/components/rich_content/rich_content.jsx'
|
||||||
import ThreadTree from 'src/components/thread_tree/thread_tree.vue'
|
import ThreadTree from 'src/components/thread_tree/thread_tree.vue'
|
||||||
|
|
||||||
import { useInterfaceStore } from 'src/stores/interface'
|
import { useInterfaceStore } from 'src/stores/interface.js'
|
||||||
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
||||||
import { useOAuthStore } from 'src/stores/oauth.js'
|
import { useOAuthStore } from 'src/stores/oauth.js'
|
||||||
|
import { useStatusesStore } from 'src/stores/statuses.js'
|
||||||
|
|
||||||
import { fetchConversation, fetchStatus } from 'src/api/public.js'
|
import { fetchConversation, fetchStatus } from 'src/api/public.js'
|
||||||
import { WSConnectionStatus } from 'src/api/websocket.js'
|
import { WSConnectionStatus } from 'src/api/websocket.js'
|
||||||
|
|
@ -51,20 +52,6 @@ const sortById = (a, b) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const sortAndFilterConversation = (conversation, statusoid) => {
|
|
||||||
if (statusoid.type === 'retweet') {
|
|
||||||
conversation = filter(
|
|
||||||
conversation,
|
|
||||||
(status) =>
|
|
||||||
status.type === 'retweet' ||
|
|
||||||
status.id !== statusoid.retweeted_status.id,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
conversation = filter(conversation, (status) => status.type !== 'retweet')
|
|
||||||
}
|
|
||||||
return conversation.filter(Boolean).sort(sortById)
|
|
||||||
}
|
|
||||||
|
|
||||||
const conversation = {
|
const conversation = {
|
||||||
props: {
|
props: {
|
||||||
statusId: {
|
statusId: {
|
||||||
|
|
@ -122,6 +109,9 @@ const conversation = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
status() {
|
||||||
|
return useStatusesStore().allStatuses.get(this.statusId)
|
||||||
|
},
|
||||||
maxDepthToShowByDefault() {
|
maxDepthToShowByDefault() {
|
||||||
// maxDepthInThread = max number of depths that is *visible*
|
// maxDepthInThread = max number of depths that is *visible*
|
||||||
// since our depth starts with 0 and "showing" means "showing children"
|
// since our depth starts with 0 and "showing" means "showing children"
|
||||||
|
|
@ -165,9 +155,6 @@ const conversation = {
|
||||||
hideStatus() {
|
hideStatus() {
|
||||||
return this.virtualHidden && this.suspendable
|
return this.virtualHidden && this.suspendable
|
||||||
},
|
},
|
||||||
status() {
|
|
||||||
return this.$store.state.statuses.allStatusesObject[this.statusId]
|
|
||||||
},
|
|
||||||
originalStatusId() {
|
originalStatusId() {
|
||||||
if (this.status.retweeted_status) {
|
if (this.status.retweeted_status) {
|
||||||
return this.status.retweeted_status.id
|
return this.status.retweeted_status.id
|
||||||
|
|
@ -187,15 +174,13 @@ const conversation = {
|
||||||
return [this.status]
|
return [this.status]
|
||||||
}
|
}
|
||||||
|
|
||||||
const conversation = clone(
|
const conversation = useStatusesStore().conversations.get(
|
||||||
this.$store.state.statuses.conversationsObject[this.conversationId],
|
this.conversationId,
|
||||||
)
|
)
|
||||||
const statusIndex = findIndex(conversation, { id: this.originalStatusId })
|
|
||||||
if (statusIndex !== -1) {
|
|
||||||
conversation[statusIndex] = this.status
|
|
||||||
}
|
|
||||||
|
|
||||||
return sortAndFilterConversation(conversation, this.status)
|
return [...conversation.keys()]
|
||||||
|
.map((k) => useStatusesStore().allStatuses.get(k))
|
||||||
|
.toSorted(sortById)
|
||||||
},
|
},
|
||||||
statusMap() {
|
statusMap() {
|
||||||
return this.conversation.reduce((res, s) => {
|
return this.conversation.reduce((res, s) => {
|
||||||
|
|
@ -441,7 +426,7 @@ const conversation = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
virtualHidden() {
|
virtualHidden() {
|
||||||
this.$store.dispatch('setVirtualHeight', {
|
useStatusesStore().setVirtualHeight({
|
||||||
statusId: this.statusId,
|
statusId: this.statusId,
|
||||||
height: `${this.$el.clientHeight}px`,
|
height: `${this.$el.clientHeight}px`,
|
||||||
})
|
})
|
||||||
|
|
@ -453,9 +438,12 @@ const conversation = {
|
||||||
fetchConversation({
|
fetchConversation({
|
||||||
id: this.statusId,
|
id: this.statusId,
|
||||||
credentials: useOAuthStore().token,
|
credentials: useOAuthStore().token,
|
||||||
}).then(({ data: { ancestors, descendants } }) => {
|
}).then(({ data: { ancestors, descendants }, timestamp }) => {
|
||||||
this.$store.dispatch('addNewStatuses', { statuses: ancestors })
|
useStatusesStore().addNewStatuses({ statuses: ancestors, timestamp })
|
||||||
this.$store.dispatch('addNewStatuses', { statuses: descendants })
|
useStatusesStore().addNewStatuses({
|
||||||
|
statuses: descendants,
|
||||||
|
timestamp,
|
||||||
|
})
|
||||||
this.setFocused(this.originalStatusId)
|
this.setFocused(this.originalStatusId)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -465,7 +453,7 @@ const conversation = {
|
||||||
credentials: useOAuthStore().token,
|
credentials: useOAuthStore().token,
|
||||||
})
|
})
|
||||||
.then(({ data: status }) => {
|
.then(({ data: status }) => {
|
||||||
this.$store.dispatch('addNewStatuses', { statuses: [status] })
|
useStatusesStore().addNewStatuses({ statuses: [status] })
|
||||||
this.fetchConversation()
|
this.fetchConversation()
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
|
|
@ -482,17 +470,17 @@ const conversation = {
|
||||||
this.focused = id
|
this.focused = id
|
||||||
|
|
||||||
if (!this.streamingEnabled) {
|
if (!this.streamingEnabled) {
|
||||||
this.$store.dispatch('fetchStatus', id)
|
useStatusesStore().fetchStatus(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
this.$store.dispatch('fetchFavsAndRepeats', id)
|
useStatusesStore().fetchFavsAndRepeats(id)
|
||||||
this.$store.dispatch('fetchEmojiReactionsBy', id)
|
useStatusesStore().fetchEmojiReactions(id)
|
||||||
},
|
},
|
||||||
toggleExpanded() {
|
toggleExpanded() {
|
||||||
this.expanded = !this.expanded
|
this.expanded = !this.expanded
|
||||||
},
|
},
|
||||||
getConversationId(statusId) {
|
getConversationId(statusId) {
|
||||||
const status = this.$store.state.statuses.allStatusesObject[statusId]
|
const status = useStatusesStore().allStatuses.get(statusId)
|
||||||
return get(
|
return get(
|
||||||
status,
|
status,
|
||||||
'retweeted_status.statusnet_conversation_id',
|
'retweeted_status.statusnet_conversation_id',
|
||||||
|
|
|
||||||
|
|
@ -99,7 +99,7 @@
|
||||||
ref="statusComponent"
|
ref="statusComponent"
|
||||||
class="conversation-status status-fadein panel-body"
|
class="conversation-status status-fadein panel-body"
|
||||||
|
|
||||||
:statusoid="status"
|
:status-id="status.id"
|
||||||
:replies="getReplies(status.id)"
|
:replies="getReplies(status.id)"
|
||||||
|
|
||||||
:expandable="!isExpanded"
|
:expandable="!isExpanded"
|
||||||
|
|
@ -152,7 +152,7 @@
|
||||||
ref="statusComponent"
|
ref="statusComponent"
|
||||||
:depth="0"
|
:depth="0"
|
||||||
|
|
||||||
:status="status"
|
:status-id="status.id"
|
||||||
:in-profile="inProfile"
|
:in-profile="inProfile"
|
||||||
:conversation="conversation"
|
:conversation="conversation"
|
||||||
:collapsable="collapsable"
|
:collapsable="collapsable"
|
||||||
|
|
@ -186,7 +186,7 @@
|
||||||
:key="status.id"
|
:key="status.id"
|
||||||
ref="statusComponent"
|
ref="statusComponent"
|
||||||
class="conversation-status status-fadein panel-body"
|
class="conversation-status status-fadein panel-body"
|
||||||
:statusoid="status"
|
:status-id="status.id"
|
||||||
:replies="getReplies(status.id)"
|
:replies="getReplies(status.id)"
|
||||||
|
|
||||||
:expandable="!isExpanded"
|
:expandable="!isExpanded"
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,10 @@ import { defineAsyncComponent } from 'vue'
|
||||||
import { useInstanceStore } from 'src/stores/instance.js'
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import { useInterfaceStore } from 'src/stores/interface'
|
import { useInterfaceStore } from 'src/stores/interface'
|
||||||
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
||||||
|
import { useStreamingStore } from 'src/stores/streaming.js'
|
||||||
|
import { useUsersStore } from 'src/stores/users.js'
|
||||||
|
|
||||||
|
import { WSConnectionStatus } from 'src/api/websocket.js'
|
||||||
|
|
||||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||||
import {
|
import {
|
||||||
|
|
@ -14,6 +18,8 @@ import {
|
||||||
faComments,
|
faComments,
|
||||||
faHome,
|
faHome,
|
||||||
faInfoCircle,
|
faInfoCircle,
|
||||||
|
faPlug,
|
||||||
|
faPlugCircleXmark,
|
||||||
faSearch,
|
faSearch,
|
||||||
faSignInAlt,
|
faSignInAlt,
|
||||||
faSignOutAlt,
|
faSignOutAlt,
|
||||||
|
|
@ -33,6 +39,8 @@ library.add(
|
||||||
faTachometerAlt,
|
faTachometerAlt,
|
||||||
faCog,
|
faCog,
|
||||||
faInfoCircle,
|
faInfoCircle,
|
||||||
|
faPlug,
|
||||||
|
faPlugCircleXmark,
|
||||||
)
|
)
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|
@ -91,11 +99,23 @@ export default {
|
||||||
sitename: (store) => store.instanceIdentity.name,
|
sitename: (store) => store.instanceIdentity.name,
|
||||||
hideSitename: (store) => store.instanceIdentity.hideSitename,
|
hideSitename: (store) => store.instanceIdentity.hideSitename,
|
||||||
}),
|
}),
|
||||||
currentUser() {
|
...mapState(useUsersStore, ['currentUser']),
|
||||||
return this.$store.state.users.currentUser
|
...mapState(useStreamingStore, {
|
||||||
},
|
streamingConnected: (store) => store.state === WSConnectionStatus.JOINED,
|
||||||
|
}),
|
||||||
|
...mapState(useMergedConfigStore, ['mergedConfig']),
|
||||||
shouldConfirmLogout() {
|
shouldConfirmLogout() {
|
||||||
return useMergedConfigStore().mergedConfig.modalOnLogout
|
return this.mergedConfig.modalOnLogout
|
||||||
|
},
|
||||||
|
streamingEnabled() {
|
||||||
|
return this.mergedConfig.useStreamingApi
|
||||||
|
},
|
||||||
|
streamingTooltip() {
|
||||||
|
if (this.streamingConnected) {
|
||||||
|
return this.$t('timeline.socket_reconnected')
|
||||||
|
} else {
|
||||||
|
return this.$t('timeline.socket_disconnected')
|
||||||
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
@ -117,7 +137,7 @@ export default {
|
||||||
},
|
},
|
||||||
doLogout() {
|
doLogout() {
|
||||||
this.$router.replace('/main/public')
|
this.$router.replace('/main/public')
|
||||||
this.$store.dispatch('logout')
|
useUsersStore().logout()
|
||||||
this.hideConfirmLogout()
|
this.hideConfirmLogout()
|
||||||
},
|
},
|
||||||
onSearchBarToggled(hidden) {
|
onSearchBarToggled(hidden) {
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,24 @@
|
||||||
>
|
>
|
||||||
{{ sitename }}
|
{{ sitename }}
|
||||||
</router-link>
|
</router-link>
|
||||||
|
<div
|
||||||
|
class="nav-icon"
|
||||||
|
v-if="streamingEnabled"
|
||||||
|
:title="streamingTooltip"
|
||||||
|
>
|
||||||
|
<FAIcon
|
||||||
|
v-if="streamingConnected"
|
||||||
|
fixed-width
|
||||||
|
class="fa-scale-110 fa-old-padding"
|
||||||
|
icon="plug"
|
||||||
|
/>
|
||||||
|
<FAIcon
|
||||||
|
v-else
|
||||||
|
fixed-width
|
||||||
|
class="fa-scale-110 fa-old-padding"
|
||||||
|
icon="plug-circle-xmark"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<router-link
|
<router-link
|
||||||
class="logo"
|
class="logo"
|
||||||
|
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
import Timeline from 'src/components/timeline/timeline.vue'
|
|
||||||
|
|
||||||
const DMs = {
|
|
||||||
computed: {
|
|
||||||
timeline() {
|
|
||||||
return this.$store.state.statuses.timelines.dms
|
|
||||||
},
|
|
||||||
},
|
|
||||||
components: {
|
|
||||||
Timeline,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
export default DMs
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
<template>
|
|
||||||
<Timeline
|
|
||||||
:title="$t('nav.dms')"
|
|
||||||
:timeline="timeline"
|
|
||||||
:timeline-name="'dms'"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script src="./dm_timeline.js"></script>
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
import ProgressButton from 'src/components/progress_button/progress_button.vue'
|
import ProgressButton from 'src/components/progress_button/progress_button.vue'
|
||||||
|
|
||||||
|
import { useUsersStore } from 'src/stores/users.js'
|
||||||
|
|
||||||
const DomainMuteCard = {
|
const DomainMuteCard = {
|
||||||
props: ['domain'],
|
props: ['domain'],
|
||||||
components: {
|
components: {
|
||||||
|
|
@ -7,7 +9,7 @@ const DomainMuteCard = {
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
user() {
|
user() {
|
||||||
return this.$store.state.users.currentUser
|
return useUsersStore().currentUser
|
||||||
},
|
},
|
||||||
muted() {
|
muted() {
|
||||||
return this.user.domainMutes.includes(this.domain)
|
return this.user.domainMutes.includes(this.domain)
|
||||||
|
|
@ -15,10 +17,10 @@ const DomainMuteCard = {
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
unmuteDomain() {
|
unmuteDomain() {
|
||||||
return this.$store.dispatch('unmuteDomain', this.domain)
|
return useUsersStore().unmuteDomain(this.domain)
|
||||||
},
|
},
|
||||||
muteDomain() {
|
muteDomain() {
|
||||||
return this.$store.dispatch('muteDomain', this.domain)
|
return useUsersStore().muteDomain(this.domain)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import PostStatusForm from 'src/components/post_status_form/post_status_form.vue
|
||||||
import StatusContent from 'src/components/status_content/status_content.vue'
|
import StatusContent from 'src/components/status_content/status_content.vue'
|
||||||
|
|
||||||
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
||||||
|
import { useStatusesStore } from 'src/stores/statuses.js'
|
||||||
|
|
||||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||||
import { faPollH } from '@fortawesome/free-solid-svg-icons'
|
import { faPollH } from '@fortawesome/free-solid-svg-icons'
|
||||||
|
|
@ -65,7 +66,7 @@ const Draft = {
|
||||||
},
|
},
|
||||||
refStatus() {
|
refStatus() {
|
||||||
return this.draft.refId
|
return this.draft.refId
|
||||||
? this.$store.state.statuses.allStatusesObject[this.draft.refId]
|
? useStatusesStore().allStatuses.get(this.draft.refId)
|
||||||
: undefined
|
: undefined
|
||||||
},
|
},
|
||||||
localCollapseSubjectDefault() {
|
localCollapseSubjectDefault() {
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import { defineAsyncComponent } from 'vue'
|
||||||
import Modal from 'src/components/modal/modal.vue'
|
import Modal from 'src/components/modal/modal.vue'
|
||||||
|
|
||||||
import { useEditStatusStore } from 'src/stores/editStatus.js'
|
import { useEditStatusStore } from 'src/stores/editStatus.js'
|
||||||
|
import { useUsersStore } from 'src/stores/users.js'
|
||||||
|
|
||||||
const EditStatusModal = {
|
const EditStatusModal = {
|
||||||
components: {
|
components: {
|
||||||
|
|
@ -19,7 +20,7 @@ const EditStatusModal = {
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
isLoggedIn() {
|
isLoggedIn() {
|
||||||
return !!this.$store.state.users.currentUser
|
return !!useUsersStore().currentUser
|
||||||
},
|
},
|
||||||
modalActivated() {
|
modalActivated() {
|
||||||
return useEditStatusStore().modalActivated
|
return useEditStatusStore().modalActivated
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { useSearchStore } from 'src/stores/search.js'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* suggest - generates a suggestor function to be used by emoji-input
|
* suggest - generates a suggestor function to be used by emoji-input
|
||||||
* data: object providing source information for specific types of suggestions:
|
* data: object providing source information for specific types of suggestions:
|
||||||
|
|
@ -77,7 +79,7 @@ export const suggestUsers = ({ dispatch, state }) => {
|
||||||
let timeout = null
|
let timeout = null
|
||||||
let cancelUserSearch = null
|
let cancelUserSearch = null
|
||||||
|
|
||||||
const userSearch = (query) => dispatch('searchUsers', { query })
|
const userSearch = (query) => useSearchStore().searchUsers({ query })
|
||||||
const debounceUserSearch = (query) => {
|
const debounceUserSearch = (query) => {
|
||||||
cancelUserSearch?.()
|
cancelUserSearch?.()
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@ import UserListPopover from 'src/components/user_list_popover/user_list_popover.
|
||||||
|
|
||||||
import { useInstanceStore } from 'src/stores/instance.js'
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
||||||
|
import { useStatusesStore } from 'src/stores/statuses.js'
|
||||||
|
import { useUsersStore } from 'src/stores/users.js'
|
||||||
|
|
||||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||||
import { faCheck, faMinus, faPlus } from '@fortawesome/free-solid-svg-icons'
|
import { faCheck, faMinus, faPlus } from '@fortawesome/free-solid-svg-icons'
|
||||||
|
|
@ -40,7 +42,7 @@ const EmojiReactions = {
|
||||||
}, {})
|
}, {})
|
||||||
},
|
},
|
||||||
loggedIn() {
|
loggedIn() {
|
||||||
return !!this.$store.state.users.currentUser
|
return !!useUsersStore().currentUser
|
||||||
},
|
},
|
||||||
remoteInteractionLink() {
|
remoteInteractionLink() {
|
||||||
return useInstanceStore().getRemoteInteractionLink({
|
return useInstanceStore().getRemoteInteractionLink({
|
||||||
|
|
@ -58,25 +60,22 @@ const EmojiReactions = {
|
||||||
reactedWith(emoji) {
|
reactedWith(emoji) {
|
||||||
return this.status.emoji_reactions.find((r) => r.name === emoji).me
|
return this.status.emoji_reactions.find((r) => r.name === emoji).me
|
||||||
},
|
},
|
||||||
async fetchEmojiReactionsByIfMissing() {
|
async fetchEmojiReactionsIfMissing() {
|
||||||
const hasNoAccounts = this.status.emoji_reactions.find((r) => !r.accounts)
|
const hasNoAccounts = this.status.emoji_reactions.find((r) => !r.accounts)
|
||||||
if (hasNoAccounts) {
|
if (!hasNoAccounts) {
|
||||||
return await this.$store.dispatch(
|
return await useStatusesStore().fetchEmojiReactions(this.status.id)
|
||||||
'fetchEmojiReactionsBy',
|
|
||||||
this.status.id,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
reactWith(emoji) {
|
reactWith(emoji) {
|
||||||
this.$store.dispatch('reactWithEmoji', { id: this.status.id, emoji })
|
useStatusesStore().reactWithEmoji(this.status.id, emoji)
|
||||||
},
|
},
|
||||||
unreact(emoji) {
|
unreact(emoji) {
|
||||||
this.$store.dispatch('unreactWithEmoji', { id: this.status.id, emoji })
|
useStatusesStore().unreactWithEmoji(this.status.id, emoji)
|
||||||
},
|
},
|
||||||
async emojiOnClick(emoji) {
|
async emojiOnClick(emoji) {
|
||||||
if (!this.loggedIn) return
|
if (!this.loggedIn) return
|
||||||
|
|
||||||
await this.fetchEmojiReactionsByIfMissing()
|
await this.fetchEmojiReactionsIfMissing()
|
||||||
if (this.reactedWith(emoji)) {
|
if (this.reactedWith(emoji)) {
|
||||||
this.unreact(emoji)
|
this.unreact(emoji)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@
|
||||||
class="emoji-reaction-popover"
|
class="emoji-reaction-popover"
|
||||||
:normal-button="true"
|
:normal-button="true"
|
||||||
:trigger-attrs="counterTriggerAttrs(reaction)"
|
:trigger-attrs="counterTriggerAttrs(reaction)"
|
||||||
@show="fetchEmojiReactionsByIfMissing()"
|
@show="fetchEmojiReactionsIfMissing()"
|
||||||
>
|
>
|
||||||
<span class="emoji-reaction-counts">{{ reaction.count }}</span>
|
<span class="emoji-reaction-counts">{{ reaction.count }}</span>
|
||||||
</UserListPopover>
|
</UserListPopover>
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import { useChatsStore } from 'src/stores/chats.js'
|
||||||
import { useInterfaceStore } from 'src/stores/interface.js'
|
import { useInterfaceStore } from 'src/stores/interface.js'
|
||||||
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
||||||
import { useSyncConfigStore } from 'src/stores/sync_config.js'
|
import { useSyncConfigStore } from 'src/stores/sync_config.js'
|
||||||
|
import { useUsersStore } from 'src/stores/users.js'
|
||||||
|
|
||||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||||
import {
|
import {
|
||||||
|
|
@ -52,7 +53,7 @@ const ExtraNotifications = {
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
currentUser() {
|
currentUser() {
|
||||||
return this.$store.state.users.currentUser
|
return useUsersStore().currentUser
|
||||||
},
|
},
|
||||||
...mapGetters(['followRequestCount']),
|
...mapGetters(['followRequestCount']),
|
||||||
...mapState(useAnnouncementsStore, {
|
...mapState(useAnnouncementsStore, {
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,8 @@
|
||||||
import { defineAsyncComponent } from 'vue'
|
import { defineAsyncComponent } from 'vue'
|
||||||
|
|
||||||
import {
|
|
||||||
requestFollow,
|
|
||||||
requestUnfollow,
|
|
||||||
} from '../../services/follow_manipulate/follow_manipulate'
|
|
||||||
|
|
||||||
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
||||||
|
import { useUsersStore } from 'src/stores/users.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: ['relationship', 'user', 'labelFollowing', 'buttonClass'],
|
props: ['relationship', 'user', 'labelFollowing', 'buttonClass'],
|
||||||
components: {
|
components: {
|
||||||
|
|
@ -64,9 +61,11 @@ export default {
|
||||||
},
|
},
|
||||||
follow() {
|
follow() {
|
||||||
this.inProgress = true
|
this.inProgress = true
|
||||||
requestFollow(this.relationship.id, this.$store).then(() => {
|
useUsersStore()
|
||||||
this.inProgress = false
|
.followUser(this.relationship.id)
|
||||||
})
|
.finally(() => {
|
||||||
|
this.inProgress = false
|
||||||
|
})
|
||||||
},
|
},
|
||||||
unfollow() {
|
unfollow() {
|
||||||
if (this.shouldConfirmUnfollow) {
|
if (this.shouldConfirmUnfollow) {
|
||||||
|
|
@ -76,15 +75,12 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
doUnfollow() {
|
doUnfollow() {
|
||||||
const store = this.$store
|
|
||||||
this.inProgress = true
|
this.inProgress = true
|
||||||
requestUnfollow(this.relationship.id, store).then(() => {
|
useUsersStore()
|
||||||
this.inProgress = false
|
.unfollowUser(this.relationship.id)
|
||||||
store.commit('removeStatus', {
|
.finally(() => {
|
||||||
timeline: 'friends',
|
this.inProgress = false
|
||||||
userId: this.relationship.id,
|
|
||||||
})
|
})
|
||||||
})
|
|
||||||
|
|
||||||
this.hideConfirmUnfollow()
|
this.hideConfirmUnfollow()
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@ import FollowButton from 'src/components/follow_button/follow_button.vue'
|
||||||
import RemoteFollow from 'src/components/remote_follow/remote_follow.vue'
|
import RemoteFollow from 'src/components/remote_follow/remote_follow.vue'
|
||||||
import RemoveFollowerButton from 'src/components/remove_follower_button/remove_follower_button.vue'
|
import RemoveFollowerButton from 'src/components/remove_follower_button/remove_follower_button.vue'
|
||||||
|
|
||||||
|
import { useUsersStore } from 'src/stores/users.js'
|
||||||
|
|
||||||
const FollowCard = {
|
const FollowCard = {
|
||||||
props: ['user', 'noFollowsYou'],
|
props: ['user', 'noFollowsYou'],
|
||||||
components: {
|
components: {
|
||||||
|
|
@ -13,13 +15,13 @@ const FollowCard = {
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
isMe() {
|
isMe() {
|
||||||
return this.$store.state.users.currentUser.id === this.user.id
|
return useUsersStore().currentUser.id === this.user.id
|
||||||
},
|
},
|
||||||
loggedIn() {
|
loggedIn() {
|
||||||
return this.$store.state.users.currentUser
|
return useUsersStore().currentUser
|
||||||
},
|
},
|
||||||
relationship() {
|
relationship() {
|
||||||
return this.$store.getters.relationship(this.user.id)
|
return useUsersStore().relationships.get(this.user.id)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<basic-user-card :user="user">
|
<BasicUserCard :user="user">
|
||||||
<div class="follow-card-content-container">
|
<div class="follow-card-content-container">
|
||||||
<span
|
<span
|
||||||
v-if="isMe || (!noFollowsYou && relationship.followed_by)"
|
v-if="isMe || (!noFollowsYou && relationship.followed_by)"
|
||||||
|
|
@ -30,7 +30,7 @@
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</basic-user-card>
|
</BasicUserCard>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script src="./follow_card.js"></script>
|
<script src="./follow_card.js"></script>
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
import { defineAsyncComponent } from 'vue'
|
import { defineAsyncComponent } from 'vue'
|
||||||
|
|
||||||
import { notificationsFromStore } from '../../services/notification_utils/notification_utils.js'
|
|
||||||
import BasicUserCard from '../basic_user_card/basic_user_card.vue'
|
import BasicUserCard from '../basic_user_card/basic_user_card.vue'
|
||||||
|
|
||||||
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
||||||
|
import { useNotificationsStore } from 'src/stores/notifications.js'
|
||||||
import { useOAuthStore } from 'src/stores/oauth.js'
|
import { useOAuthStore } from 'src/stores/oauth.js'
|
||||||
|
|
||||||
import { approveUser, denyUser } from 'src/api/user.js'
|
import { approveUser, denyUser } from 'src/api/user.js'
|
||||||
|
|
@ -24,7 +24,7 @@ const FollowRequestCard = {
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
findFollowRequestNotificationId() {
|
findFollowRequestNotificationId() {
|
||||||
const notif = notificationsFromStore(this.$store).find(
|
const notif = useNotificationsStore().data.find(
|
||||||
(notif) =>
|
(notif) =>
|
||||||
notif.from_profile.id === this.user.id &&
|
notif.from_profile.id === this.user.id &&
|
||||||
notif.type === 'follow_request',
|
notif.type === 'follow_request',
|
||||||
|
|
@ -55,16 +55,11 @@ const FollowRequestCard = {
|
||||||
id: this.user.id,
|
id: this.user.id,
|
||||||
credentials: useOAuthStore().token,
|
credentials: useOAuthStore().token,
|
||||||
})
|
})
|
||||||
|
// TODO fix
|
||||||
this.$store.dispatch('removeFollowRequest', this.user)
|
this.$store.dispatch('removeFollowRequest', this.user)
|
||||||
|
|
||||||
const notifId = this.findFollowRequestNotificationId()
|
const notifId = this.findFollowRequestNotificationId()
|
||||||
this.$store.dispatch('markSingleNotificationAsSeen', { id: notifId })
|
useNotificationsStore().markSingleNotificationAsSeen(notifId)
|
||||||
this.$store.dispatch('updateNotification', {
|
|
||||||
id: notifId,
|
|
||||||
updater: (notification) => {
|
|
||||||
notification.type = 'follow'
|
|
||||||
},
|
|
||||||
})
|
|
||||||
this.hideApproveConfirmDialog()
|
this.hideApproveConfirmDialog()
|
||||||
},
|
},
|
||||||
denyUser() {
|
denyUser() {
|
||||||
|
|
@ -81,7 +76,8 @@ const FollowRequestCard = {
|
||||||
id: this.user.id,
|
id: this.user.id,
|
||||||
credentials: useOAuthStore().token,
|
credentials: useOAuthStore().token,
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
this.$store.dispatch('dismissNotificationLocal', { id: notifId })
|
useNotificationsStore().dismissNotificationLocal(notifId)
|
||||||
|
// TODO fix
|
||||||
this.$store.dispatch('removeFollowRequest', this.user)
|
this.$store.dispatch('removeFollowRequest', this.user)
|
||||||
})
|
})
|
||||||
this.hideDenyConfirmDialog()
|
this.hideDenyConfirmDialog()
|
||||||
|
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
import Timeline from 'src/components/timeline/timeline.vue'
|
|
||||||
|
|
||||||
const FriendsTimeline = {
|
|
||||||
components: {
|
|
||||||
Timeline,
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
timeline() {
|
|
||||||
return this.$store.state.statuses.timelines.friends
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
export default FriendsTimeline
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
<template>
|
|
||||||
<Timeline
|
|
||||||
:title="$t('nav.timeline')"
|
|
||||||
:timeline="timeline"
|
|
||||||
:timeline-name="'friends'"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script src="./friends_timeline.js"></script>
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
import Notifications from 'src/components/notifications/notifications.vue'
|
import Notifications from 'src/components/notifications/notifications.vue'
|
||||||
import TabSwitcher from 'src/components/tab_switcher/tab_switcher.jsx'
|
import TabSwitcher from 'src/components/tab_switcher/tab_switcher.jsx'
|
||||||
|
|
||||||
|
import { useUsersStore } from 'src/stores/users.js'
|
||||||
|
|
||||||
const tabModeDict = {
|
const tabModeDict = {
|
||||||
mentions: ['mention'],
|
mentions: ['mention'],
|
||||||
statuses: ['status'],
|
statuses: ['status'],
|
||||||
|
|
@ -14,10 +16,9 @@ const tabModeDict = {
|
||||||
const Interactions = {
|
const Interactions = {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
allowFollowingMove:
|
allowFollowingMove: useUsersStore().currentUser.allow_following_move,
|
||||||
this.$store.state.users.currentUser.allow_following_move,
|
|
||||||
filterMode: tabModeDict.mentions,
|
filterMode: tabModeDict.mentions,
|
||||||
canSeeReports: this.$store.state.users.currentUser.privileges.has(
|
canSeeReports: useUsersStore().currentUser.privileges.has(
|
||||||
'reports_manage_reports',
|
'reports_manage_reports',
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -98,12 +98,13 @@ const List = {
|
||||||
|
|
||||||
this.fetchFunction(this.page)
|
this.fetchFunction(this.page)
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
|
console.log(result)
|
||||||
this.loading = false
|
this.loading = false
|
||||||
this.bottomedOut = isEmpty(result.items)
|
this.bottomedOut = isEmpty(result)
|
||||||
if (this.externalItems) return
|
if (this.externalItems) return
|
||||||
this.page += 1
|
this.page += 1
|
||||||
this.total = result.count
|
this.total = result.length
|
||||||
this.items.push(...result.items)
|
this.items.push(...result)
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
this.loading = false
|
this.loading = false
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import { mapState as mapPiniaState } from 'pinia'
|
import { mapState } from 'pinia'
|
||||||
import { mapGetters, mapState } from 'vuex'
|
|
||||||
|
|
||||||
import BasicUserCard from 'src/components/basic_user_card/basic_user_card.vue'
|
import BasicUserCard from 'src/components/basic_user_card/basic_user_card.vue'
|
||||||
import ListsUserSearch from 'src/components/lists_user_search/lists_user_search.vue'
|
import ListsUserSearch from 'src/components/lists_user_search/lists_user_search.vue'
|
||||||
|
|
@ -9,6 +8,7 @@ import UserAvatar from 'src/components/user_avatar/user_avatar.vue'
|
||||||
|
|
||||||
import { useInterfaceStore } from 'src/stores/interface.js'
|
import { useInterfaceStore } from 'src/stores/interface.js'
|
||||||
import { useListsStore } from 'src/stores/lists.js'
|
import { useListsStore } from 'src/stores/lists.js'
|
||||||
|
import { useUsersStore } from 'src/stores/users.js'
|
||||||
|
|
||||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||||
import { faChevronLeft, faSearch } from '@fortawesome/free-solid-svg-icons'
|
import { faChevronLeft, faSearch } from '@fortawesome/free-solid-svg-icons'
|
||||||
|
|
@ -47,8 +47,8 @@ const ListsNew = {
|
||||||
.fetchListAccounts({ listId: this.id })
|
.fetchListAccounts({ listId: this.id })
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.membersUserIds = this.findListAccounts(this.id)
|
this.membersUserIds = this.findListAccounts(this.id)
|
||||||
this.membersUserIds.forEach((userId) => {
|
this.membersUserIds.forEach((id) => {
|
||||||
this.$store.dispatch('fetchUserIfMissing', userId)
|
useUsersStore().fetchUserIfMissing({ id })
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
@ -66,11 +66,8 @@ const ListsNew = {
|
||||||
.map((userId) => this.findUser(userId))
|
.map((userId) => this.findUser(userId))
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
},
|
},
|
||||||
...mapState({
|
...mapState(useUsersStore, ['currentUser', 'findUser']),
|
||||||
currentUser: (state) => state.users.currentUser,
|
...mapState(useListsStore, ['findListTitle', 'findListAccounts']),
|
||||||
}),
|
|
||||||
...mapPiniaState(useListsStore, ['findListTitle', 'findListAccounts']),
|
|
||||||
...mapGetters(['findUser']),
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
onInput() {
|
onInput() {
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
import { mapState as mapPiniaState } from 'pinia'
|
import { mapState } from 'pinia'
|
||||||
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 { useListsStore } from 'src/stores/lists.js'
|
import { useListsStore } from 'src/stores/lists.js'
|
||||||
|
import { useUsersStore } from 'src/stores/users.js'
|
||||||
|
|
||||||
export const ListsMenuContent = {
|
export const ListsMenuContent = {
|
||||||
props: ['showPin'],
|
props: ['showPin'],
|
||||||
|
|
@ -12,12 +12,10 @@ export const ListsMenuContent = {
|
||||||
NavigationEntry,
|
NavigationEntry,
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapPiniaState(useListsStore, {
|
...mapState(useListsStore, {
|
||||||
lists: getListEntries,
|
lists: getListEntries,
|
||||||
}),
|
}),
|
||||||
...mapState({
|
...mapState(useUsersStore, ['currentUser']),
|
||||||
currentUser: (state) => state.users.currentUser,
|
|
||||||
}),
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,47 +0,0 @@
|
||||||
import Timeline from 'src/components/timeline/timeline.vue'
|
|
||||||
|
|
||||||
import { useListsStore } from 'src/stores/lists.js'
|
|
||||||
|
|
||||||
const ListsTimeline = {
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
listId: null,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
components: {
|
|
||||||
Timeline,
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
timeline() {
|
|
||||||
return this.$store.state.statuses.timelines.list
|
|
||||||
},
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
$route: function (route) {
|
|
||||||
if (route.name === 'lists-timeline' && route.params.id !== this.listId) {
|
|
||||||
this.listId = route.params.id
|
|
||||||
this.$store.dispatch('stopFetchingTimeline', 'list')
|
|
||||||
this.$store.commit('clearTimeline', { timeline: 'list' })
|
|
||||||
useListsStore().fetchList({ listId: this.listId })
|
|
||||||
this.$store.dispatch('startFetchingTimeline', {
|
|
||||||
timeline: 'list',
|
|
||||||
listId: this.listId,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
created() {
|
|
||||||
this.listId = this.$route.params.id
|
|
||||||
useListsStore().fetchList({ listId: this.listId })
|
|
||||||
this.$store.dispatch('startFetchingTimeline', {
|
|
||||||
timeline: 'list',
|
|
||||||
listId: this.listId,
|
|
||||||
})
|
|
||||||
},
|
|
||||||
unmounted() {
|
|
||||||
this.$store.dispatch('stopFetchingTimeline', 'list')
|
|
||||||
this.$store.commit('clearTimeline', { timeline: 'list' })
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
export default ListsTimeline
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
<template>
|
|
||||||
<Timeline
|
|
||||||
title="list.name"
|
|
||||||
:timeline="timeline"
|
|
||||||
:list-id="listId"
|
|
||||||
timeline-name="list"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script src="./lists_timeline.js"></script>
|
|
||||||
|
|
@ -32,8 +32,8 @@ const ListsUserSearch = {
|
||||||
this.loading = true
|
this.loading = true
|
||||||
this.$emit('loading')
|
this.$emit('loading')
|
||||||
this.userIds = []
|
this.userIds = []
|
||||||
this.$store
|
this.useSearchStore()
|
||||||
.dispatch('search', {
|
.search({
|
||||||
q: query,
|
q: query,
|
||||||
resolve: true,
|
resolve: true,
|
||||||
type: 'accounts',
|
type: 'accounts',
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import { mapState as mapPiniaState } from 'pinia'
|
import { mapState } from 'pinia'
|
||||||
import { mapState } from 'vuex'
|
|
||||||
|
|
||||||
import UnicodeDomainIndicator from 'src/components/unicode_domain_indicator/unicode_domain_indicator.vue'
|
import UnicodeDomainIndicator from 'src/components/unicode_domain_indicator/unicode_domain_indicator.vue'
|
||||||
import UserAvatar from 'src/components/user_avatar/user_avatar.vue'
|
import UserAvatar from 'src/components/user_avatar/user_avatar.vue'
|
||||||
|
|
@ -12,6 +11,7 @@ import {
|
||||||
import { useInstanceStore } from 'src/stores/instance.js'
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
||||||
import { useUserHighlightStore } from 'src/stores/user_highlight.js'
|
import { useUserHighlightStore } from 'src/stores/user_highlight.js'
|
||||||
|
import { useUsersStore } from 'src/stores/users.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'
|
||||||
|
|
||||||
|
|
@ -75,7 +75,7 @@ const MentionLink = {
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
user() {
|
user() {
|
||||||
return this.url && this.$store?.getters.findUserByUrl(this.url)
|
return this.url && useUsersStore().findUserByUrl(this.url)
|
||||||
},
|
},
|
||||||
isYou() {
|
isYou() {
|
||||||
// FIXME why user !== currentUser???
|
// FIXME why user !== currentUser???
|
||||||
|
|
@ -156,11 +156,9 @@ const MentionLink = {
|
||||||
shouldFadeDomain() {
|
shouldFadeDomain() {
|
||||||
return this.mergedConfig.mentionLinkFadeDomain
|
return this.mergedConfig.mentionLinkFadeDomain
|
||||||
},
|
},
|
||||||
...mapPiniaState(useMergedConfigStore, ['mergedConfig']),
|
...mapState(useMergedConfigStore, ['mergedConfig']),
|
||||||
...mapPiniaState(useUserHighlightStore, ['highlight']),
|
...mapState(useUserHighlightStore, ['highlight']),
|
||||||
...mapState({
|
...mapState(useUsersStore, ['currentUser']),
|
||||||
currentUser: (state) => state.users.currentUser,
|
|
||||||
}),
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@
|
||||||
<UserAvatar
|
<UserAvatar
|
||||||
v-if="shouldShowAvatar"
|
v-if="shouldShowAvatar"
|
||||||
class="mention-avatar"
|
class="mention-avatar"
|
||||||
:user="user"
|
:user-id="user.id"
|
||||||
/><span
|
/><span
|
||||||
class="shortName"
|
class="shortName"
|
||||||
>@<span
|
>@<span
|
||||||
|
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
import Timeline from 'src/components/timeline/timeline.vue'
|
|
||||||
|
|
||||||
const Mentions = {
|
|
||||||
computed: {
|
|
||||||
timeline() {
|
|
||||||
return this.$store.state.statuses.timelines.mentions
|
|
||||||
},
|
|
||||||
},
|
|
||||||
components: {
|
|
||||||
Timeline,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Mentions
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
<template>
|
|
||||||
<Timeline
|
|
||||||
:title="$t('nav.interactions')"
|
|
||||||
:timeline="timeline"
|
|
||||||
:timeline-name="'mentions'"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script src="./mentions.js"></script>
|
|
||||||
|
|
@ -5,13 +5,15 @@ import NavigationPins from 'src/components/navigation/navigation_pins.vue'
|
||||||
import GestureService from '../../services/gesture_service/gesture_service'
|
import GestureService from '../../services/gesture_service/gesture_service'
|
||||||
import {
|
import {
|
||||||
countExtraNotifications,
|
countExtraNotifications,
|
||||||
unseenNotificationsFromStore,
|
unseenNotifications,
|
||||||
} from '../../services/notification_utils/notification_utils'
|
} from '../../services/notification_utils/notification_utils'
|
||||||
|
|
||||||
import { useAnnouncementsStore } from 'src/stores/announcements.js'
|
import { useAnnouncementsStore } from 'src/stores/announcements.js'
|
||||||
import { useChatsStore } from 'src/stores/chats.js'
|
import { useChatsStore } from 'src/stores/chats.js'
|
||||||
import { useInstanceStore } from 'src/stores/instance.js'
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
||||||
|
import { useNotificationsStore } from 'src/stores/notifications.js'
|
||||||
|
import { useUsersStore } from 'src/stores/users.js'
|
||||||
|
|
||||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||||
import {
|
import {
|
||||||
|
|
@ -53,11 +55,10 @@ const MobileNav = {
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
currentUser() {
|
currentUser() {
|
||||||
return this.$store.state.users.currentUser
|
return useUsersStore().currentUser
|
||||||
},
|
},
|
||||||
unseenNotifications() {
|
unseenNotifications() {
|
||||||
return unseenNotificationsFromStore(
|
return unseenNotifications(
|
||||||
this.$store,
|
|
||||||
useMergedConfigStore().mergedConfig.notificationVisibility,
|
useMergedConfigStore().mergedConfig.notificationVisibility,
|
||||||
useMergedConfigStore().mergedConfig.ignoreInactionableSeen,
|
useMergedConfigStore().mergedConfig.ignoreInactionableSeen,
|
||||||
)
|
)
|
||||||
|
|
@ -145,11 +146,11 @@ const MobileNav = {
|
||||||
},
|
},
|
||||||
doLogout() {
|
doLogout() {
|
||||||
this.$router.replace('/main/public')
|
this.$router.replace('/main/public')
|
||||||
this.$store.dispatch('logout')
|
useUsersStore().logout()
|
||||||
this.hideConfirmLogout()
|
this.hideConfirmLogout()
|
||||||
},
|
},
|
||||||
markNotificationsAsSeen() {
|
markNotificationsAsSeen() {
|
||||||
this.$store.dispatch('markNotificationsAsSeen')
|
useNotificationsStore().markNotificationsAsSeen()
|
||||||
},
|
},
|
||||||
onScroll({ target: { scrollTop, clientHeight, scrollHeight } }) {
|
onScroll({ target: { scrollTop, clientHeight, scrollHeight } }) {
|
||||||
this.notificationsAtTop = scrollTop > 0
|
this.notificationsAtTop = scrollTop > 0
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import { debounce } from 'lodash'
|
||||||
|
|
||||||
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
||||||
import { usePostStatusStore } from 'src/stores/post_status.js'
|
import { usePostStatusStore } from 'src/stores/post_status.js'
|
||||||
|
import { useUsersStore } from 'src/stores/users.js'
|
||||||
|
|
||||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||||
import { faPen } from '@fortawesome/free-solid-svg-icons'
|
import { faPen } from '@fortawesome/free-solid-svg-icons'
|
||||||
|
|
@ -34,7 +35,7 @@ const MobilePostStatusButton = {
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
isLoggedIn() {
|
isLoggedIn() {
|
||||||
return !!this.$store.state.users.currentUser
|
return useUsersStore().loggedIn
|
||||||
},
|
},
|
||||||
isHidden() {
|
isHidden() {
|
||||||
if (HIDDEN_FOR_PAGES.has(this.$route.name)) {
|
if (HIDDEN_FOR_PAGES.has(this.$route.name)) {
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import Popover from 'src/components/popover/popover.vue'
|
||||||
|
|
||||||
import { useAdminSettingsStore } from 'src/stores/admin_settings.js'
|
import { useAdminSettingsStore } from 'src/stores/admin_settings.js'
|
||||||
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
|
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
|
||||||
|
import { useUsersStore } from 'src/stores/users.js'
|
||||||
|
|
||||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||||
import { faChevronDown } from '@fortawesome/free-solid-svg-icons'
|
import { faChevronDown } from '@fortawesome/free-solid-svg-icons'
|
||||||
|
|
@ -405,7 +406,7 @@ const ModerationTools = {
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
isAdmin() {
|
isAdmin() {
|
||||||
return this.$store.state.users.currentUser.role === 'admin'
|
return useUsersStore().currentUser.role === 'admin'
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
@ -452,7 +453,7 @@ const ModerationTools = {
|
||||||
},
|
},
|
||||||
privileged(privilege) {
|
privileged(privilege) {
|
||||||
if (this.isAdmin) return true
|
if (this.isAdmin) return true
|
||||||
return this.$store.state.users.currentUser.privileges.has(privilege)
|
return useUsersStore().currentUser.privileges.has(privilege)
|
||||||
},
|
},
|
||||||
setTag(tag, value) {
|
setTag(tag, value) {
|
||||||
useAdminSettingsStore().setUsersTags({
|
useAdminSettingsStore().setUsersTags({
|
||||||
|
|
@ -516,8 +517,7 @@ const ModerationTools = {
|
||||||
setOpen(value) {
|
setOpen(value) {
|
||||||
this.open = value
|
this.open = value
|
||||||
},
|
},
|
||||||
maybeShowConfirm(close, { group, name, action, value }) {
|
maybeShowConfirm({ group, name, action, value }) {
|
||||||
close()
|
|
||||||
this.confirmDialogName = name
|
this.confirmDialogName = name
|
||||||
this.confirmDialogGroup = group
|
this.confirmDialogGroup = group
|
||||||
this.confirmDialogAction = () => action()
|
this.confirmDialogAction = () => action()
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@
|
||||||
@show="setOpen(true)"
|
@show="setOpen(true)"
|
||||||
@close="setOpen(false)"
|
@close="setOpen(false)"
|
||||||
>
|
>
|
||||||
<template #content="{close}">
|
<template #content>
|
||||||
<div class="dropdown-menu">
|
<div class="dropdown-menu">
|
||||||
<template v-for="(entry, index) in entries">
|
<template v-for="(entry, index) in entries">
|
||||||
<div
|
<div
|
||||||
|
|
@ -26,7 +26,7 @@
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
class="main-button"
|
class="main-button"
|
||||||
@click="() => maybeShowConfirm(close, entry)"
|
@click="() => maybeShowConfirm(entry)"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
v-if="entry.checkbox"
|
v-if="entry.checkbox"
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,16 @@
|
||||||
import BasicUserCard from 'src/components/basic_user_card/basic_user_card.vue'
|
import BasicUserCard from 'src/components/basic_user_card/basic_user_card.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 { useUsersStore } from 'src/stores/users.js'
|
||||||
|
|
||||||
const MuteCard = {
|
const MuteCard = {
|
||||||
props: ['userId'],
|
props: ['userId'],
|
||||||
computed: {
|
computed: {
|
||||||
user() {
|
user() {
|
||||||
return this.$store.getters.findUser(this.userId)
|
return useUsersStore().findUser(this.userId)
|
||||||
},
|
},
|
||||||
relationship() {
|
relationship() {
|
||||||
return this.$store.getters.relationship(this.userId)
|
return useUsersStore().relationship(this.userId)
|
||||||
},
|
},
|
||||||
muted() {
|
muted() {
|
||||||
return this.relationship.muting
|
return this.relationship.muting
|
||||||
|
|
@ -30,7 +32,7 @@ const MuteCard = {
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
unmuteUser() {
|
unmuteUser() {
|
||||||
this.$store.dispatch('unmuteUser', this.userId)
|
useUsersStore().unmuteUser(this.user.id)
|
||||||
},
|
},
|
||||||
muteUser() {
|
muteUser() {
|
||||||
this.$refs.timedMuteDialog.optionallyPrompt()
|
this.$refs.timedMuteDialog.optionallyPrompt()
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ import { useChatsStore } from 'src/stores/chats.js'
|
||||||
import { useInstanceStore } from 'src/stores/instance.js'
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
|
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
|
||||||
import { useSyncConfigStore } from 'src/stores/sync_config.js'
|
import { useSyncConfigStore } from 'src/stores/sync_config.js'
|
||||||
|
import { useUsersStore } from 'src/stores/users.js'
|
||||||
|
|
||||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||||
import {
|
import {
|
||||||
|
|
@ -128,8 +129,8 @@ const NavPanel = {
|
||||||
pinnedItems: (store) =>
|
pinnedItems: (store) =>
|
||||||
new Set(store.prefsStorage.collections.pinnedNavItems),
|
new Set(store.prefsStorage.collections.pinnedNavItems),
|
||||||
}),
|
}),
|
||||||
|
...mapPiniaState(useUsersStore, ['currentUser']),
|
||||||
...mapState({
|
...mapState({
|
||||||
currentUser: (state) => state.users.currentUser,
|
|
||||||
followRequestCount: (state) => state.api.followRequests.length,
|
followRequestCount: (state) => state.api.followRequests.length,
|
||||||
}),
|
}),
|
||||||
...mapPiniaState(useChatsStore, ['unreadChatsCount']),
|
...mapPiniaState(useChatsStore, ['unreadChatsCount']),
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
import { mapState as mapPiniaState, mapStores } from 'pinia'
|
import { mapState, mapStores } from 'pinia'
|
||||||
import { mapState } from 'vuex'
|
|
||||||
|
|
||||||
import { routeTo } from 'src/components/navigation/navigation.js'
|
import { routeTo } from 'src/components/navigation/navigation.js'
|
||||||
import OptionalRouterLink from 'src/components/optional_router_link/optional_router_link.vue'
|
import OptionalRouterLink from 'src/components/optional_router_link/optional_router_link.vue'
|
||||||
|
|
||||||
import { useAnnouncementsStore } from 'src/stores/announcements.js'
|
import { useAnnouncementsStore } from 'src/stores/announcements.js'
|
||||||
import { useSyncConfigStore } from 'src/stores/sync_config.js'
|
import { useSyncConfigStore } from 'src/stores/sync_config.js'
|
||||||
|
import { useUsersStore } from 'src/stores/users.js'
|
||||||
|
|
||||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||||
import { faThumbtack } from '@fortawesome/free-solid-svg-icons'
|
import { faThumbtack } from '@fortawesome/free-solid-svg-icons'
|
||||||
|
|
@ -44,10 +44,8 @@ const NavigationEntry = {
|
||||||
return this.$store.getters
|
return this.$store.getters
|
||||||
},
|
},
|
||||||
...mapStores(useAnnouncementsStore),
|
...mapStores(useAnnouncementsStore),
|
||||||
...mapState({
|
...mapState(useUsersStore, ['currentUser']),
|
||||||
currentUser: (state) => state.users.currentUser,
|
...mapState(useSyncConfigStore, {
|
||||||
}),
|
|
||||||
...mapPiniaState(useSyncConfigStore, {
|
|
||||||
pinnedItems: (store) =>
|
pinnedItems: (store) =>
|
||||||
new Set(store.prefsStorage.collections.pinnedNavItems),
|
new Set(store.prefsStorage.collections.pinnedNavItems),
|
||||||
}),
|
}),
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
|
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
|
||||||
import { useListsStore } from 'src/stores/lists'
|
import { useListsStore } from 'src/stores/lists'
|
||||||
import { useSyncConfigStore } from 'src/stores/sync_config.js'
|
import { useSyncConfigStore } from 'src/stores/sync_config.js'
|
||||||
|
import { useUsersStore } from 'src/stores/users.js'
|
||||||
|
|
||||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||||
import {
|
import {
|
||||||
|
|
@ -76,8 +77,8 @@ const NavPanel = {
|
||||||
'pleromaChatMessagesAvailable',
|
'pleromaChatMessagesAvailable',
|
||||||
'localBubble',
|
'localBubble',
|
||||||
]),
|
]),
|
||||||
|
...mapPiniaState(useUsersStore, ['currentUser']),
|
||||||
...mapState({
|
...mapState({
|
||||||
currentUser: (state) => state.users.currentUser,
|
|
||||||
followRequestCount: (state) => state.api.followRequests.length,
|
followRequestCount: (state) => state.api.followRequests.length,
|
||||||
}),
|
}),
|
||||||
pinnedList() {
|
pinnedList() {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
|
import { mapState } from 'pinia'
|
||||||
import { defineAsyncComponent } from 'vue'
|
import { defineAsyncComponent } from 'vue'
|
||||||
import { mapState } from 'vuex'
|
|
||||||
|
|
||||||
import Report from 'src/components/report/report.vue'
|
import Report from 'src/components/report/report.vue'
|
||||||
import StatusContent from 'src/components/status_content/status_content.vue'
|
import StatusContent from 'src/components/status_content/status_content.vue'
|
||||||
|
|
@ -7,7 +7,7 @@ import Timeago from 'src/components/timeago/timeago.vue'
|
||||||
import UserAvatar from 'src/components/user_avatar/user_avatar.vue'
|
import UserAvatar from 'src/components/user_avatar/user_avatar.vue'
|
||||||
import UserLink from 'src/components/user_link/user_link.vue'
|
import UserLink from 'src/components/user_link/user_link.vue'
|
||||||
import UserPopover from 'src/components/user_popover/user_popover.vue'
|
import UserPopover from 'src/components/user_popover/user_popover.vue'
|
||||||
import { isStatusNotification } from '../../services/notification_utils/notification_utils.js'
|
import { isStatusNotification } from '../../services/notification_utils/notification_utils_sw.js'
|
||||||
import {
|
import {
|
||||||
highlightClass,
|
highlightClass,
|
||||||
highlightStyle,
|
highlightStyle,
|
||||||
|
|
@ -15,8 +15,11 @@ import {
|
||||||
|
|
||||||
import { useInstanceStore } from 'src/stores/instance.js'
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
||||||
|
import { useNotificationsStore } from 'src/stores/notifications.js'
|
||||||
import { useOAuthStore } from 'src/stores/oauth.js'
|
import { useOAuthStore } from 'src/stores/oauth.js'
|
||||||
|
import { useStatusesStore } from 'src/stores/statuses.js'
|
||||||
import { useUserHighlightStore } from 'src/stores/user_highlight.js'
|
import { useUserHighlightStore } from 'src/stores/user_highlight.js'
|
||||||
|
import { useUsersStore } from 'src/stores/users.js'
|
||||||
|
|
||||||
import { approveUser, denyUser } from 'src/api/user.js'
|
import { approveUser, denyUser } from 'src/api/user.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'
|
||||||
|
|
@ -148,16 +151,9 @@ const Notification = {
|
||||||
id: this.user.id,
|
id: this.user.id,
|
||||||
credentials: useOAuthStore().token,
|
credentials: useOAuthStore().token,
|
||||||
})
|
})
|
||||||
|
// TODO Fix this
|
||||||
this.$store.dispatch('removeFollowRequest', this.user)
|
this.$store.dispatch('removeFollowRequest', this.user)
|
||||||
this.$store.dispatch('markSingleNotificationAsSeen', {
|
useNotificationsStore().markSingleNotificationAsSeen(this.notification.id)
|
||||||
id: this.notification.id,
|
|
||||||
})
|
|
||||||
this.$store.dispatch('updateNotification', {
|
|
||||||
id: this.notification.id,
|
|
||||||
updater: (notification) => {
|
|
||||||
notification.type = 'follow'
|
|
||||||
},
|
|
||||||
})
|
|
||||||
this.hideApproveConfirmDialog()
|
this.hideApproveConfirmDialog()
|
||||||
},
|
},
|
||||||
denyUser() {
|
denyUser() {
|
||||||
|
|
@ -172,15 +168,20 @@ const Notification = {
|
||||||
id: this.user.id,
|
id: this.user.id,
|
||||||
credentials: useOAuthStore().token,
|
credentials: useOAuthStore().token,
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
this.$store.dispatch('dismissNotificationLocal', {
|
useNotificationsStore().dismissNotificationLocal(this.notification.id)
|
||||||
id: this.notification.id,
|
// TODO Fix this
|
||||||
})
|
|
||||||
this.$store.dispatch('removeFollowRequest', this.user)
|
this.$store.dispatch('removeFollowRequest', this.user)
|
||||||
})
|
})
|
||||||
this.hideDenyConfirmDialog()
|
this.hideDenyConfirmDialog()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
status() {
|
||||||
|
// Used for StatusContent
|
||||||
|
if (this.notification.status) {
|
||||||
|
return useStatusesStore().allStatuses.get(this.notification.status.id)
|
||||||
|
}
|
||||||
|
},
|
||||||
userClass() {
|
userClass() {
|
||||||
return highlightClass(this.notification.from_profile)
|
return highlightClass(this.notification.from_profile)
|
||||||
},
|
},
|
||||||
|
|
@ -194,19 +195,19 @@ const Notification = {
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
user() {
|
user() {
|
||||||
return this.$store.getters.findUser(this.notification.from_profile.id)
|
return useUsersStore().findUser(this.notification.from_profile.id)
|
||||||
},
|
},
|
||||||
userProfileLink() {
|
userProfileLink() {
|
||||||
return this.generateUserProfileLink(this.user)
|
return this.generateUserProfileLink(this.user)
|
||||||
},
|
},
|
||||||
targetUser() {
|
targetUser() {
|
||||||
return this.$store.getters.findUser(this.notification.target.id)
|
return useUsersStore().findUser(this.notification.target.id)
|
||||||
},
|
},
|
||||||
targetUserProfileLink() {
|
targetUserProfileLink() {
|
||||||
return this.generateUserProfileLink(this.targetUser)
|
return this.generateUserProfileLink(this.targetUser)
|
||||||
},
|
},
|
||||||
needMute() {
|
needMute() {
|
||||||
return this.$store.getters.relationship(this.user.id).muting
|
return useUsersStore().relationship(this.user.id).muting
|
||||||
},
|
},
|
||||||
isStatusNotification() {
|
isStatusNotification() {
|
||||||
return isStatusNotification(this.notification.type)
|
return isStatusNotification(this.notification.type)
|
||||||
|
|
@ -229,9 +230,7 @@ const Notification = {
|
||||||
shouldConfirmDeny() {
|
shouldConfirmDeny() {
|
||||||
return this.mergedConfig.modalOnDenyFollow
|
return this.mergedConfig.modalOnDenyFollow
|
||||||
},
|
},
|
||||||
...mapState({
|
...mapState(useUsersStore, ['currentUser']),
|
||||||
currentUser: (state) => state.users.currentUser,
|
|
||||||
}),
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
<Status
|
<Status
|
||||||
class="Notification panel-body"
|
class="Notification panel-body"
|
||||||
:compact="true"
|
:compact="true"
|
||||||
:statusoid="notification.status"
|
:status-id="notification.status?.id"
|
||||||
@click="interacted"
|
@click="interacted"
|
||||||
/>
|
/>
|
||||||
</article>
|
</article>
|
||||||
|
|
@ -57,7 +57,7 @@
|
||||||
<UserAvatar
|
<UserAvatar
|
||||||
class="post-avatar"
|
class="post-avatar"
|
||||||
:compact="true"
|
:compact="true"
|
||||||
:user="notification.from_profile"
|
:user-id="notification.from_profile.id"
|
||||||
/>
|
/>
|
||||||
</UserPopover>
|
</UserPopover>
|
||||||
</a>
|
</a>
|
||||||
|
|
@ -261,7 +261,7 @@
|
||||||
<StatusContent
|
<StatusContent
|
||||||
class="status-content"
|
class="status-content"
|
||||||
:compact="!statusExpanded"
|
:compact="!statusExpanded"
|
||||||
:status="notification.status"
|
:status="status"
|
||||||
:collapse="!statusExpanded"
|
:collapse="!statusExpanded"
|
||||||
@click="onContentClick"
|
@click="onContentClick"
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -7,17 +7,16 @@ import FaviconService from '../../services/favicon_service/favicon_service.js'
|
||||||
import {
|
import {
|
||||||
ACTIONABLE_NOTIFICATION_TYPES,
|
ACTIONABLE_NOTIFICATION_TYPES,
|
||||||
countExtraNotifications,
|
countExtraNotifications,
|
||||||
filteredNotificationsFromStore,
|
filteredNotifications,
|
||||||
notificationsFromStore,
|
unseenNotifications,
|
||||||
unseenNotificationsFromStore,
|
|
||||||
} from '../../services/notification_utils/notification_utils.js'
|
} from '../../services/notification_utils/notification_utils.js'
|
||||||
import notificationsFetcher from '../../services/notifications_fetcher/notifications_fetcher.service.js'
|
|
||||||
import NotificationFilters from './notification_filters.vue'
|
import NotificationFilters from './notification_filters.vue'
|
||||||
|
|
||||||
import { useAnnouncementsStore } from 'src/stores/announcements.js'
|
import { useAnnouncementsStore } from 'src/stores/announcements.js'
|
||||||
import { useChatsStore } from 'src/stores/chats.js'
|
import { useChatsStore } from 'src/stores/chats.js'
|
||||||
import { useInterfaceStore } from 'src/stores/interface.js'
|
import { useInterfaceStore } from 'src/stores/interface.js'
|
||||||
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
||||||
|
import { useNotificationsStore } from 'src/stores/notifications.js'
|
||||||
|
|
||||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||||
import {
|
import {
|
||||||
|
|
@ -53,7 +52,6 @@ const Notifications = {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
showScrollTop: false,
|
showScrollTop: false,
|
||||||
bottomedOut: false,
|
|
||||||
// How many seen notifications to display in the list. The more there are,
|
// How many seen notifications to display in the list. The more there are,
|
||||||
// the heavier the page becomes. This count is increased when loading
|
// the heavier the page becomes. This count is increased when loading
|
||||||
// older notifications, and cut back to default whenever hitting "Read!".
|
// older notifications, and cut back to default whenever hitting "Read!".
|
||||||
|
|
@ -70,14 +68,13 @@ const Notifications = {
|
||||||
return this.minimalMode ? '' : 'panel panel-default'
|
return this.minimalMode ? '' : 'panel panel-default'
|
||||||
},
|
},
|
||||||
notifications() {
|
notifications() {
|
||||||
return notificationsFromStore(this.$store)
|
return useNotificationsStore().data
|
||||||
},
|
},
|
||||||
error() {
|
error() {
|
||||||
return this.$store.state.notifications.error
|
return useNotificationsStore().error
|
||||||
},
|
},
|
||||||
unseenNotifications() {
|
unseenNotifications() {
|
||||||
return unseenNotificationsFromStore(
|
return unseenNotifications(
|
||||||
this.$store,
|
|
||||||
useMergedConfigStore().mergedConfig.notificationVisibility,
|
useMergedConfigStore().mergedConfig.notificationVisibility,
|
||||||
useMergedConfigStore().mergedConfig.ignoreInactionableSeen,
|
useMergedConfigStore().mergedConfig.ignoreInactionableSeen,
|
||||||
)
|
)
|
||||||
|
|
@ -85,18 +82,15 @@ const Notifications = {
|
||||||
filteredNotifications() {
|
filteredNotifications() {
|
||||||
if (this.unseenAtTop) {
|
if (this.unseenAtTop) {
|
||||||
return [
|
return [
|
||||||
...filteredNotificationsFromStore(
|
...filteredNotifications(
|
||||||
this.$store,
|
|
||||||
useMergedConfigStore().mergedConfig.notificationVisibility,
|
useMergedConfigStore().mergedConfig.notificationVisibility,
|
||||||
).filter((n) => this.shouldShowUnseen(n)),
|
).filter((n) => this.shouldShowUnseen(n)),
|
||||||
...filteredNotificationsFromStore(
|
...filteredNotifications(
|
||||||
this.$store,
|
|
||||||
useMergedConfigStore().mergedConfig.notificationVisibility,
|
useMergedConfigStore().mergedConfig.notificationVisibility,
|
||||||
).filter((n) => !this.shouldShowUnseen(n)),
|
).filter((n) => !this.shouldShowUnseen(n)),
|
||||||
]
|
]
|
||||||
} else {
|
} else {
|
||||||
return filteredNotificationsFromStore(
|
return filteredNotifications(
|
||||||
this.$store,
|
|
||||||
useMergedConfigStore().mergedConfig.notificationVisibility,
|
useMergedConfigStore().mergedConfig.notificationVisibility,
|
||||||
this.filterMode,
|
this.filterMode,
|
||||||
)
|
)
|
||||||
|
|
@ -127,7 +121,10 @@ const Notifications = {
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
loading() {
|
loading() {
|
||||||
return this.$store.state.notifications.loading
|
return useNotificationsStore().fetcher.loading.value
|
||||||
|
},
|
||||||
|
bottomedOut() {
|
||||||
|
return useNotificationsStore().fetcher.bottomedOut.value
|
||||||
},
|
},
|
||||||
noHeading() {
|
noHeading() {
|
||||||
const { layoutType } = useInterfaceStore()
|
const { layoutType } = useInterfaceStore()
|
||||||
|
|
@ -224,14 +221,14 @@ const Notifications = {
|
||||||
*/
|
*/
|
||||||
notificationClicked(notification) {
|
notificationClicked(notification) {
|
||||||
const { id } = notification
|
const { id } = notification
|
||||||
this.$store.dispatch('notificationClicked', { id })
|
useNotificationsStore().notificationClicked(id)
|
||||||
},
|
},
|
||||||
notificationInteracted(notification) {
|
notificationInteracted(notification) {
|
||||||
const { id } = notification
|
const { id } = notification
|
||||||
this.$store.dispatch('markSingleNotificationAsSeen', { id })
|
useNotificationsStore().markSingleNotificationAsSeen(id)
|
||||||
},
|
},
|
||||||
markAsSeen() {
|
markAsSeen() {
|
||||||
this.$store.dispatch('markNotificationsAsSeen')
|
useNotificationsStore().markNotificationsAsSeen()
|
||||||
this.seenToDisplayCount = DEFAULT_SEEN_TO_DISPLAY_COUNT
|
this.seenToDisplayCount = DEFAULT_SEEN_TO_DISPLAY_COUNT
|
||||||
},
|
},
|
||||||
fetchOlderNotifications() {
|
fetchOlderNotifications() {
|
||||||
|
|
@ -250,22 +247,7 @@ const Notifications = {
|
||||||
this.seenToDisplayCount = seenCount
|
this.seenToDisplayCount = seenCount
|
||||||
}
|
}
|
||||||
|
|
||||||
const store = this.$store
|
useNotificationsStore().fetcher.fetchOlder()
|
||||||
const credentials = store.state.users.currentUser.credentials
|
|
||||||
store.commit('setNotificationsLoading', { value: true })
|
|
||||||
notificationsFetcher
|
|
||||||
.fetchAndUpdate({
|
|
||||||
store,
|
|
||||||
credentials,
|
|
||||||
older: true,
|
|
||||||
})
|
|
||||||
.then((notifs) => {
|
|
||||||
store.commit('setNotificationsLoading', { value: false })
|
|
||||||
if (notifs.length === 0) {
|
|
||||||
this.bottomedOut = true
|
|
||||||
}
|
|
||||||
this.seenToDisplayCount += notifs.length
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import { useInstanceStore } from 'src/stores/instance.js'
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import { useOAuthStore } from 'src/stores/oauth.js'
|
import { useOAuthStore } from 'src/stores/oauth.js'
|
||||||
|
import { useUsersStore } from 'src/stores/users.js'
|
||||||
|
|
||||||
import { getToken } from 'src/api/oauth.js'
|
import { getToken } from 'src/api/oauth.js'
|
||||||
|
|
||||||
|
|
@ -17,7 +18,8 @@ const oac = {
|
||||||
code: this.code,
|
code: this.code,
|
||||||
}).then(({ data: result }) => {
|
}).then(({ data: result }) => {
|
||||||
oauthStore.setToken(result.access_token)
|
oauthStore.setToken(result.access_token)
|
||||||
this.$store.dispatch('loginUser', result.access_token)
|
|
||||||
|
useUsersStore().loginUser(result.access_token)
|
||||||
this.$router.push({ name: 'friends' })
|
this.$router.push({ name: 'friends' })
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { mapState as mapPiniaState } from 'pinia'
|
import { mapState } from 'pinia'
|
||||||
import { mapState } from 'vuex'
|
|
||||||
|
|
||||||
import { useInstanceStore } from 'src/stores/instance.js'
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
|
import { useUsersStore } from 'src/stores/users.js'
|
||||||
|
|
||||||
import { resetPassword } from 'src/api/public.js'
|
import { resetPassword } from 'src/api/public.js'
|
||||||
|
|
||||||
|
|
@ -21,13 +21,11 @@ const passwordReset = {
|
||||||
error: null,
|
error: null,
|
||||||
}),
|
}),
|
||||||
computed: {
|
computed: {
|
||||||
...mapState({
|
...mapState(useUsersStore, ['loggedIn']),
|
||||||
signedIn: (state) => !!state.users.currentUser,
|
...mapState(useInstanceStore, ['mailerEnabled']),
|
||||||
}),
|
|
||||||
...mapPiniaState(useInstanceStore, ['mailerEnabled']),
|
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
if (this.signedIn) {
|
if (this.loggedIn) {
|
||||||
this.$router.push({ name: 'root' })
|
this.$router.push({ name: 'root' })
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import genRandomSeed from '../../services/random_seed/random_seed.service.js'
|
||||||
|
|
||||||
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
||||||
import { usePollsStore } from 'src/stores/polls.js'
|
import { usePollsStore } from 'src/stores/polls.js'
|
||||||
|
import { useUsersStore } from 'src/stores/users.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Poll',
|
name: 'Poll',
|
||||||
|
|
@ -64,7 +65,7 @@ export default {
|
||||||
return useMergedConfigStore().mergedConfig.scaleMfm
|
return useMergedConfigStore().mergedConfig.scaleMfm
|
||||||
},
|
},
|
||||||
loggedIn() {
|
loggedIn() {
|
||||||
return this.$store.state.users.currentUser
|
return useUsersStore().currentUser
|
||||||
},
|
},
|
||||||
showResults() {
|
showResults() {
|
||||||
return this.poll.voted || this.expired || !this.loggedIn
|
return this.poll.voted || this.expired || !this.loggedIn
|
||||||
|
|
|
||||||
|
|
@ -78,8 +78,8 @@
|
||||||
v-model="expiryUnit"
|
v-model="expiryUnit"
|
||||||
unstyled="true"
|
unstyled="true"
|
||||||
class="expiry-unit"
|
class="expiry-unit"
|
||||||
@change="expiryAmountChange"
|
|
||||||
:aria-label="$t('polls.expiry_unit')"
|
:aria-label="$t('polls.expiry_unit')"
|
||||||
|
@change="expiryAmountChange"
|
||||||
>
|
>
|
||||||
<option
|
<option
|
||||||
v-for="unit in expiryUnits"
|
v-for="unit in expiryUnits"
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ import { useInterfaceStore } from 'src/stores/interface.js'
|
||||||
import { useMediaViewerStore } from 'src/stores/media_viewer.js'
|
import { useMediaViewerStore } from 'src/stores/media_viewer.js'
|
||||||
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
||||||
import { useSyncConfigStore } from 'src/stores/sync_config.js'
|
import { useSyncConfigStore } from 'src/stores/sync_config.js'
|
||||||
|
import { useUsersStore } from 'src/stores/users.js'
|
||||||
|
|
||||||
import { pollFormToMasto } from 'src/services/poll/poll.service.js'
|
import { pollFormToMasto } from 'src/services/poll/poll.service.js'
|
||||||
|
|
||||||
|
|
@ -570,17 +571,18 @@ const PostStatusForm = {
|
||||||
},
|
},
|
||||||
|
|
||||||
// Global stuff
|
// Global stuff
|
||||||
currentUser() {
|
...mapState(useUsersStore, ['currentUser']),
|
||||||
return this.$store.state.users.currentUser
|
|
||||||
},
|
|
||||||
...mapState(useMergedConfigStore, ['mergedConfig']),
|
...mapState(useMergedConfigStore, ['mergedConfig']),
|
||||||
...mapState(useInterfaceStore, {
|
...mapState(useInterfaceStore, {
|
||||||
mobileLayout: (store) => store.mobileLayout,
|
mobileLayout: (store) => store.mobileLayout,
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
isDirty(newVal, oldVal) {
|
newStatus: {
|
||||||
this.statusChanged()
|
deep: true,
|
||||||
|
handler() {
|
||||||
|
this.statusChanged()
|
||||||
|
},
|
||||||
},
|
},
|
||||||
saveable(val) {
|
saveable(val) {
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/API/Window/beforeunload_event#usage_notes
|
// https://developer.mozilla.org/en-US/docs/Web/API/Window/beforeunload_event#usage_notes
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import Modal from 'src/components/modal/modal.vue'
|
||||||
import PostStatusForm from 'src/components/post_status_form/post_status_form.vue'
|
import PostStatusForm from 'src/components/post_status_form/post_status_form.vue'
|
||||||
|
|
||||||
import { usePostStatusStore } from 'src/stores/post_status.js'
|
import { usePostStatusStore } from 'src/stores/post_status.js'
|
||||||
|
import { useUsersStore } from 'src/stores/users.js'
|
||||||
|
|
||||||
const PostStatusModal = {
|
const PostStatusModal = {
|
||||||
components: {
|
components: {
|
||||||
|
|
@ -17,7 +18,7 @@ const PostStatusModal = {
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
isLoggedIn() {
|
isLoggedIn() {
|
||||||
return !!this.$store.state.users.currentUser
|
return !!useUsersStore().currentUser
|
||||||
},
|
},
|
||||||
modalActivated() {
|
modalActivated() {
|
||||||
return usePostStatusStore().modalActivated
|
return usePostStatusStore().modalActivated
|
||||||
|
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
import Timeline from 'src/components/timeline/timeline.vue'
|
|
||||||
|
|
||||||
const PublicAndExternalTimeline = {
|
|
||||||
components: {
|
|
||||||
Timeline,
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
timeline() {
|
|
||||||
return this.$store.state.statuses.timelines.publicAndExternal
|
|
||||||
},
|
|
||||||
},
|
|
||||||
created() {
|
|
||||||
this.$store.dispatch('startFetchingTimeline', {
|
|
||||||
timeline: 'publicAndExternal',
|
|
||||||
})
|
|
||||||
},
|
|
||||||
unmounted() {
|
|
||||||
this.$store.dispatch('stopFetchingTimeline', 'publicAndExternal')
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
export default PublicAndExternalTimeline
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
<template>
|
|
||||||
<Timeline
|
|
||||||
:title="$t('nav.twkn')"
|
|
||||||
:timeline="timeline"
|
|
||||||
:timeline-name="'publicAndExternal'"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script src="./public_and_external_timeline.js"></script>
|
|
||||||
|
|
@ -1,20 +0,0 @@
|
||||||
import Timeline from 'src/components/timeline/timeline.vue'
|
|
||||||
|
|
||||||
const PublicTimeline = {
|
|
||||||
components: {
|
|
||||||
Timeline,
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
timeline() {
|
|
||||||
return this.$store.state.statuses.timelines.public
|
|
||||||
},
|
|
||||||
},
|
|
||||||
created() {
|
|
||||||
this.$store.dispatch('startFetchingTimeline', { timeline: 'public' })
|
|
||||||
},
|
|
||||||
unmounted() {
|
|
||||||
this.$store.dispatch('stopFetchingTimeline', 'public')
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
export default PublicTimeline
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
<template>
|
|
||||||
<Timeline
|
|
||||||
:title="$t('nav.public_tl')"
|
|
||||||
:timeline="timeline"
|
|
||||||
:timeline-name="'public'"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script src="./public_timeline.js"></script>
|
|
||||||
|
|
@ -5,7 +5,9 @@ import Popover from 'src/components/popover/popover.vue'
|
||||||
import { useInterfaceStore } from 'src/stores/interface.js'
|
import { useInterfaceStore } from 'src/stores/interface.js'
|
||||||
import { useLocalConfigStore } from 'src/stores/local_config.js'
|
import { useLocalConfigStore } from 'src/stores/local_config.js'
|
||||||
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
||||||
|
import { useStatusesStore } from 'src/stores/statuses.js'
|
||||||
import { useSyncConfigStore } from 'src/stores/sync_config.js'
|
import { useSyncConfigStore } from 'src/stores/sync_config.js'
|
||||||
|
import { useUsersStore } from 'src/stores/users.js'
|
||||||
|
|
||||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||||
import { faFilter, faFont, faWrench } from '@fortawesome/free-solid-svg-icons'
|
import { faFilter, faFont, faWrench } from '@fortawesome/free-solid-svg-icons'
|
||||||
|
|
@ -26,7 +28,7 @@ const QuickFilterSettings = {
|
||||||
path: 'replyVisibility',
|
path: 'replyVisibility',
|
||||||
value: visibility,
|
value: visibility,
|
||||||
})
|
})
|
||||||
this.$store.dispatch('queueFlushAll')
|
useStatusesStore().queueFlushAll()
|
||||||
},
|
},
|
||||||
openTab(tab) {
|
openTab(tab) {
|
||||||
useInterfaceStore().openSettingsModalTab(tab)
|
useInterfaceStore().openSettingsModalTab(tab)
|
||||||
|
|
@ -54,7 +56,7 @@ const QuickFilterSettings = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
loggedIn() {
|
loggedIn() {
|
||||||
return !!this.$store.state.users.currentUser
|
return !!useUsersStore().currentUser
|
||||||
},
|
},
|
||||||
replyVisibilitySelf: {
|
replyVisibilitySelf: {
|
||||||
get() {
|
get() {
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import QuickFilterSettings from 'src/components/quick_filter_settings/quick_filt
|
||||||
import { useInterfaceStore } from 'src/stores/interface.js'
|
import { useInterfaceStore } from 'src/stores/interface.js'
|
||||||
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
||||||
import { useSyncConfigStore } from 'src/stores/sync_config.js'
|
import { useSyncConfigStore } from 'src/stores/sync_config.js'
|
||||||
|
import { useUsersStore } from 'src/stores/users.js'
|
||||||
|
|
||||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||||
import {
|
import {
|
||||||
|
|
@ -36,7 +37,7 @@ const QuickViewSettings = {
|
||||||
mobileLayout: (state) => state.layoutType === 'mobile',
|
mobileLayout: (state) => state.layoutType === 'mobile',
|
||||||
}),
|
}),
|
||||||
loggedIn() {
|
loggedIn() {
|
||||||
return !!this.$store.state.users.currentUser
|
return !!useUsersStore().currentUser
|
||||||
},
|
},
|
||||||
conversationDisplay: {
|
conversationDisplay: {
|
||||||
get() {
|
get() {
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { useStatusesStore } from 'src/stores/statuses.js'
|
||||||
|
|
||||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||||
import { faCircleNotch } from '@fortawesome/free-solid-svg-icons'
|
import { faCircleNotch } from '@fortawesome/free-solid-svg-icons'
|
||||||
|
|
||||||
|
|
@ -45,7 +47,7 @@ export default {
|
||||||
computed: {
|
computed: {
|
||||||
quotedStatus() {
|
quotedStatus() {
|
||||||
return this.statusId
|
return this.statusId
|
||||||
? this.$store.state.statuses.allStatusesObject[this.statusId]
|
? useStatusesStore().allStatuses.get(this.statusId)
|
||||||
: undefined
|
: undefined
|
||||||
},
|
},
|
||||||
shouldDisplayQuote() {
|
shouldDisplayQuote() {
|
||||||
|
|
@ -79,8 +81,8 @@ export default {
|
||||||
this.fetchAttempted = true
|
this.fetchAttempted = true
|
||||||
this.fetching = true
|
this.fetching = true
|
||||||
this.$emit('loading', true)
|
this.$emit('loading', true)
|
||||||
this.$store
|
useStatusesStore()
|
||||||
.dispatch('fetchStatus', this.statusId)
|
.fetchStatus(this.statusId)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.displayQuote = true
|
this.displayQuote = true
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -93,8 +93,8 @@ export default {
|
||||||
this.$emit('update:id', notice[3])
|
this.$emit('update:id', notice[3])
|
||||||
} else if (value) {
|
} else if (value) {
|
||||||
this.loading = true
|
this.loading = true
|
||||||
this.$store
|
this.useSearchStore()
|
||||||
.dispatch('search', {
|
.search({
|
||||||
q: value,
|
q: value,
|
||||||
resolve: true,
|
resolve: true,
|
||||||
offset: 0,
|
offset: 0,
|
||||||
|
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
import Timeline from 'src/components/timeline/timeline.vue'
|
|
||||||
|
|
||||||
const QuotesTimeline = {
|
|
||||||
created() {
|
|
||||||
this.$store.commit('clearTimeline', { timeline: 'quotes' })
|
|
||||||
this.$store.dispatch('startFetchingTimeline', {
|
|
||||||
timeline: 'quotes',
|
|
||||||
statusId: this.statusId,
|
|
||||||
})
|
|
||||||
},
|
|
||||||
components: {
|
|
||||||
Timeline,
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
statusId() {
|
|
||||||
return this.$route.params.id
|
|
||||||
},
|
|
||||||
timeline() {
|
|
||||||
return this.$store.state.statuses.timelines.quotes
|
|
||||||
},
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
statusId() {
|
|
||||||
this.$store.commit('clearTimeline', { timeline: 'quotes' })
|
|
||||||
this.$store.dispatch('startFetchingTimeline', {
|
|
||||||
timeline: 'quotes',
|
|
||||||
statusId: this.statusId,
|
|
||||||
})
|
|
||||||
},
|
|
||||||
},
|
|
||||||
unmounted() {
|
|
||||||
this.$store.dispatch('stopFetchingTimeline', 'quotes')
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
export default QuotesTimeline
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
<template>
|
|
||||||
<Timeline
|
|
||||||
:title="$t('nav.quotes')"
|
|
||||||
:timeline="timeline"
|
|
||||||
:timeline-name="'quotes'"
|
|
||||||
:status-id="statusId"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script src='./quotes_timeline.js'></script>
|
|
||||||
|
|
@ -1,14 +1,16 @@
|
||||||
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 'pinia'
|
||||||
import { mapActions, mapState } from 'vuex'
|
|
||||||
|
|
||||||
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 TermsOfServicePanel from 'src/components/terms_of_service_panel/terms_of_service_panel.vue'
|
import TermsOfServicePanel from 'src/components/terms_of_service_panel/terms_of_service_panel.vue'
|
||||||
import localeService from '../../services/locale/locale.service.js'
|
import localeService from '../../services/locale/locale.service.js'
|
||||||
|
|
||||||
import { useInstanceStore } from 'src/stores/instance.js'
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
|
import { useOAuthStore } from 'src/stores/oauth.js'
|
||||||
|
import { useUsersStore } from 'src/stores/users.js'
|
||||||
|
|
||||||
|
import { getCaptcha, register } from 'src/api/public.js'
|
||||||
import { DAY } from 'src/services/date_utils/date_utils.js'
|
import { DAY } from 'src/services/date_utils/date_utils.js'
|
||||||
|
|
||||||
const registration = {
|
const registration = {
|
||||||
|
|
@ -26,6 +28,9 @@ const registration = {
|
||||||
reason: '',
|
reason: '',
|
||||||
language: [''],
|
language: [''],
|
||||||
},
|
},
|
||||||
|
signUpPending: false,
|
||||||
|
signUpErrors: [],
|
||||||
|
signUpNotice: {},
|
||||||
captcha: {},
|
captcha: {},
|
||||||
}),
|
}),
|
||||||
components: {
|
components: {
|
||||||
|
|
@ -58,7 +63,7 @@ const registration = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
if ((!this.registrationOpen && !this.token) || this.signedIn) {
|
if ((!this.registrationOpen && !this.token) || this.loggedIn) {
|
||||||
this.$router.push({ name: 'root' })
|
this.$router.push({ name: 'root' })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -100,7 +105,10 @@ const registration = {
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
...mapPiniaState(useInstanceStore, {
|
hasSignUpNotice(state) {
|
||||||
|
return this.signUpNotice.message
|
||||||
|
},
|
||||||
|
...mapState(useInstanceStore, {
|
||||||
registrationOpen: (store) => store.registrationOpen,
|
registrationOpen: (store) => store.registrationOpen,
|
||||||
embeddedToS: (store) => store.embeddedToS,
|
embeddedToS: (store) => store.embeddedToS,
|
||||||
termsOfService: (store) => store.tos,
|
termsOfService: (store) => store.tos,
|
||||||
|
|
@ -109,16 +117,49 @@ const registration = {
|
||||||
birthdayRequired: (store) => store.birthdayRequired,
|
birthdayRequired: (store) => store.birthdayRequired,
|
||||||
birthdayMinAge: (store) => store.birthdayMinAge,
|
birthdayMinAge: (store) => store.birthdayMinAge,
|
||||||
}),
|
}),
|
||||||
...mapState({
|
...mapState(useUsersStore, ['loggedIn']),
|
||||||
signedIn: (state) => !!state.users.currentUser,
|
|
||||||
isPending: (state) => state.users.signUpPending,
|
|
||||||
serverValidationErrors: (state) => state.users.signUpErrors,
|
|
||||||
signUpNotice: (state) => state.users.signUpNotice,
|
|
||||||
hasSignUpNotice: (state) => !!state.users.signUpNotice.message,
|
|
||||||
}),
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
...mapActions(['signUp', 'getCaptcha']),
|
...mapActions(useUsersStore, ['loginUser']),
|
||||||
|
getCaptcha(store) {
|
||||||
|
return getCaptcha({
|
||||||
|
credentials: useOAuthStore().token,
|
||||||
|
}).then(({ data }) => data)
|
||||||
|
},
|
||||||
|
async signUp(userInfo) {
|
||||||
|
const oauthStore = useOAuthStore()
|
||||||
|
|
||||||
|
this.signUpPending = true
|
||||||
|
this.signUpErrors = []
|
||||||
|
this.signUpNotice = {}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const token = await oauthStore.ensureAppToken()
|
||||||
|
const { data } = await register({
|
||||||
|
credentials: token,
|
||||||
|
params: { ...userInfo },
|
||||||
|
})
|
||||||
|
|
||||||
|
if (data.access_token) {
|
||||||
|
this.signUpPending = false
|
||||||
|
oauthStore.setToken(data.access_token)
|
||||||
|
await this.loginUser(data.access_token)
|
||||||
|
return 'ok'
|
||||||
|
} else {
|
||||||
|
// Request succeeded, but user cannot login yet.
|
||||||
|
this.signUpErrors = []
|
||||||
|
this.signUpNotice = data
|
||||||
|
return 'request_sent'
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
const errors = e.message
|
||||||
|
this.signUpErrors = errors
|
||||||
|
this.signUpNotice = {}
|
||||||
|
throw e
|
||||||
|
} finally {
|
||||||
|
this.signUpPending = false
|
||||||
|
}
|
||||||
|
},
|
||||||
async submit() {
|
async submit() {
|
||||||
this.user.nickname = this.user.username
|
this.user.nickname = this.user.username
|
||||||
this.user.token = this.token
|
this.user.token = this.token
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue