Merge branch 'fix/timeline-error-handling-fixes' into 'develop'

Various timeline fixes

See merge request pleroma/pleroma-fe!1283
This commit is contained in:
Shpuld Shpludson 2020-11-18 11:49:54 +00:00
commit d770bab1b0
11 changed files with 41 additions and 78 deletions

View file

@ -7,6 +7,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [Unreleased] ## [Unreleased]
### Fixed ### Fixed
- Fixed the occasional bug where screen would scroll 1px when typing into a reply form - Fixed the occasional bug where screen would scroll 1px when typing into a reply form
- Fixed timeline errors locking timelines
### Changed
- Errors when fetching are now shown with popup errors instead of "Error fetching updates" in panel headers
- Fixed custom emoji not working in profile field names - Fixed custom emoji not working in profile field names
- Fixed pinned statuses not appearing in user profiles - Fixed pinned statuses not appearing in user profiles

View file

@ -15,13 +15,6 @@
class="badge badge-notification unseen-count" class="badge badge-notification unseen-count"
>{{ unseenCount }}</span> >{{ unseenCount }}</span>
</div> </div>
<div
v-if="error"
class="loadmore-error alert error"
@click.prevent
>
{{ $t('timeline.error_fetching') }}
</div>
<button <button
v-if="unseenCount" v-if="unseenCount"
class="read-button" class="read-button"

View file

@ -50,17 +50,10 @@ const Timeline = {
TimelineMenu TimelineMenu
}, },
computed: { computed: {
timelineError () {
return this.$store.state.statuses.error
},
errorData () {
return this.$store.state.statuses.errorData
},
newStatusCount () { newStatusCount () {
return this.timeline.newStatusCount return this.timeline.newStatusCount
}, },
showLoadButton () { showLoadButton () {
if (this.timelineError || this.errorData) return false
return this.timeline.newStatusCount > 0 || this.timeline.flushMarker !== 0 return this.timeline.newStatusCount > 0 || this.timeline.flushMarker !== 0
}, },
loadButtonString () { loadButtonString () {
@ -171,11 +164,12 @@ const Timeline = {
userId: this.userId, userId: this.userId,
tag: this.tag tag: this.tag
}).then(({ statuses }) => { }).then(({ statuses }) => {
store.commit('setLoading', { timeline: this.timelineName, value: false })
if (statuses && statuses.length === 0) { if (statuses && statuses.length === 0) {
this.bottomedOut = true this.bottomedOut = true
} }
}) }).finally(() =>
store.commit('setLoading', { timeline: this.timelineName, value: false })
)
}, 1000, this), }, 1000, this),
determineVisibleStatuses () { determineVisibleStatuses () {
if (!this.$refs.timeline) return if (!this.$refs.timeline) return

View file

@ -2,22 +2,8 @@
<div :class="[classes.root, 'Timeline']"> <div :class="[classes.root, 'Timeline']">
<div :class="classes.header"> <div :class="classes.header">
<TimelineMenu v-if="!embedded" /> <TimelineMenu v-if="!embedded" />
<div
v-if="timelineError"
class="loadmore-error alert error"
@click.prevent
>
{{ $t('timeline.error_fetching') }}
</div>
<div
v-else-if="errorData"
class="loadmore-error alert error"
@click.prevent
>
{{ errorData.statusText }}
</div>
<button <button
v-else-if="showLoadButton" v-if="showLoadButton"
class="loadmore-button" class="loadmore-button"
@click.prevent="showNewStatuses" @click.prevent="showNewStatuses"
> >
@ -76,18 +62,12 @@
{{ $t('timeline.no_more_statuses') }} {{ $t('timeline.no_more_statuses') }}
</div> </div>
<a <a
v-else-if="!timeline.loading && !errorData" v-else-if="!timeline.loading"
href="#" href="#"
@click.prevent="fetchOlderStatuses()" @click.prevent="fetchOlderStatuses()"
> >
<div class="new-status-notification text-center panel-footer">{{ $t('timeline.load_older') }}</div> <div class="new-status-notification text-center panel-footer">{{ $t('timeline.load_older') }}</div>
</a> </a>
<a
v-else-if="errorData"
href="#"
>
<div class="new-status-notification text-center panel-footer">{{ errorData.error }}</div>
</a>
<div <div
v-else v-else
class="new-status-notification text-center panel-footer" class="new-status-notification text-center panel-footer"

View file

@ -19,7 +19,7 @@ library.add(
faChevronDown faChevronDown
) )
// Route -> i18n key mapping, exported andnot in the computed // Route -> i18n key mapping, exported and not in the computed
// because nav panel benefits from the same information. // because nav panel benefits from the same information.
export const timelineNames = () => { export const timelineNames = () => {
return { return {
@ -27,8 +27,7 @@ export const timelineNames = () => {
'bookmarks': 'nav.bookmarks', 'bookmarks': 'nav.bookmarks',
'dms': 'nav.dms', 'dms': 'nav.dms',
'public-timeline': 'nav.public_tl', 'public-timeline': 'nav.public_tl',
'public-external-timeline': 'nav.twkn', 'public-external-timeline': 'nav.twkn'
'tag-timeline': 'tag'
} }
} }

View file

@ -130,6 +130,7 @@
}, },
"notifications": { "notifications": {
"broken_favorite": "Unknown status, searching for it…", "broken_favorite": "Unknown status, searching for it…",
"error": "Error fetching notifications: {0}",
"favorited_you": "favorited your status", "favorited_you": "favorited your status",
"followed_you": "followed you", "followed_you": "followed you",
"follow_request": "wants to follow you", "follow_request": "wants to follow you",
@ -634,7 +635,7 @@
"timeline": { "timeline": {
"collapse": "Collapse", "collapse": "Collapse",
"conversation": "Conversation", "conversation": "Conversation",
"error_fetching": "Error fetching updates", "error": "Error fetching timeline: {0}",
"load_older": "Load older statuses", "load_older": "Load older statuses",
"no_retweet_hint": "Post is marked as followers-only or direct and cannot be repeated", "no_retweet_hint": "Post is marked as followers-only or direct and cannot be repeated",
"repeated": "repeated", "repeated": "repeated",

View file

@ -39,8 +39,7 @@ const emptyNotifications = () => ({
minId: Number.POSITIVE_INFINITY, minId: Number.POSITIVE_INFINITY,
data: [], data: [],
idStore: {}, idStore: {},
loading: false, loading: false
error: false
}) })
export const defaultState = () => ({ export const defaultState = () => ({
@ -50,8 +49,6 @@ export const defaultState = () => ({
maxId: 0, maxId: 0,
notifications: emptyNotifications(), notifications: emptyNotifications(),
favorites: new Set(), favorites: new Set(),
error: false,
errorData: null,
timelines: { timelines: {
mentions: emptyTl(), mentions: emptyTl(),
public: emptyTl(), public: emptyTl(),
@ -462,18 +459,9 @@ export const mutations = {
const newStatus = state.allStatusesObject[id] const newStatus = state.allStatusesObject[id]
newStatus.nsfw = nsfw newStatus.nsfw = nsfw
}, },
setError (state, { value }) {
state.error = value
},
setErrorData (state, { value }) {
state.errorData = value
},
setNotificationsLoading (state, { value }) { setNotificationsLoading (state, { value }) {
state.notifications.loading = value state.notifications.loading = value
}, },
setNotificationsError (state, { value }) {
state.notifications.error = value
},
setNotificationsSilence (state, { value }) { setNotificationsSilence (state, { value }) {
state.notifications.desktopNotificationSilence = value state.notifications.desktopNotificationSilence = value
}, },
@ -588,18 +576,9 @@ const statuses = {
} }
commit('addNewNotifications', { dispatch, notifications, older, rootGetters, newNotificationSideEffects }) commit('addNewNotifications', { dispatch, notifications, older, rootGetters, newNotificationSideEffects })
}, },
setError ({ rootState, commit }, { value }) {
commit('setError', { value })
},
setErrorData ({ rootState, commit }, { value }) {
commit('setErrorData', { value })
},
setNotificationsLoading ({ rootState, commit }, { value }) { setNotificationsLoading ({ rootState, commit }, { value }) {
commit('setNotificationsLoading', { value }) commit('setNotificationsLoading', { value })
}, },
setNotificationsError ({ rootState, commit }, { value }) {
commit('setNotificationsError', { value })
},
setNotificationsSilence ({ rootState, commit }, { value }) { setNotificationsSilence ({ rootState, commit }, { value }) {
commit('setNotificationsSilence', { value }) commit('setNotificationsSilence', { value })
}, },

View file

@ -560,7 +560,7 @@ const fetchTimeline = ({
}) })
.then((data) => data.json()) .then((data) => data.json())
.then((data) => { .then((data) => {
if (!data.error) { if (!data.errors) {
return { data: data.map(isNotifications ? parseNotification : parseStatus), pagination } return { data: data.map(isNotifications ? parseNotification : parseStatus), pagination }
} else { } else {
data.status = status data.status = status

View file

@ -2,7 +2,6 @@ import apiService from '../api/api.service.js'
import { promiseInterval } from '../promise_interval/promise_interval.js' import { promiseInterval } from '../promise_interval/promise_interval.js'
const update = ({ store, notifications, older }) => { const update = ({ store, notifications, older }) => {
store.dispatch('setNotificationsError', { value: false })
store.dispatch('addNewNotifications', { notifications, older }) store.dispatch('addNewNotifications', { notifications, older })
} }
@ -47,11 +46,22 @@ const fetchAndUpdate = ({ store, credentials, older = false }) => {
const fetchNotifications = ({ store, args, older }) => { const fetchNotifications = ({ store, args, older }) => {
return apiService.fetchTimeline(args) return apiService.fetchTimeline(args)
.then(({ data: notifications }) => { .then((response) => {
if (response.errors) {
throw new Error(`${response.status} ${response.statusText}`)
}
const notifications = response.data
update({ store, notifications, older }) update({ store, notifications, older })
return notifications return notifications
}, () => store.dispatch('setNotificationsError', { value: true })) })
.catch(() => store.dispatch('setNotificationsError', { value: true })) .catch((error) => {
store.dispatch('pushGlobalNotice', {
level: 'error',
messageKey: 'notifications.error',
messageArgs: [error.message],
timeout: 5000
})
})
} }
const startFetching = ({ credentials, store }) => { const startFetching = ({ credentials, store }) => {

View file

@ -6,9 +6,6 @@ import { promiseInterval } from '../promise_interval/promise_interval.js'
const update = ({ store, statuses, timeline, showImmediately, userId, pagination }) => { const update = ({ store, statuses, timeline, showImmediately, userId, pagination }) => {
const ccTimeline = camelCase(timeline) const ccTimeline = camelCase(timeline)
store.dispatch('setError', { value: false })
store.dispatch('setErrorData', { value: null })
store.dispatch('addNewStatuses', { store.dispatch('addNewStatuses', {
timeline: ccTimeline, timeline: ccTimeline,
userId, userId,
@ -52,9 +49,8 @@ const fetchAndUpdate = ({
return apiService.fetchTimeline(args) return apiService.fetchTimeline(args)
.then(response => { .then(response => {
if (response.error) { if (response.errors) {
store.dispatch('setErrorData', { value: response }) throw new Error(`${response.status} ${response.statusText}`)
return
} }
const { data: statuses, pagination } = response const { data: statuses, pagination } = response
@ -63,7 +59,15 @@ const fetchAndUpdate = ({
} }
update({ store, statuses, timeline, showImmediately, userId, pagination }) update({ store, statuses, timeline, showImmediately, userId, pagination })
return { statuses, pagination } return { statuses, pagination }
}, () => store.dispatch('setError', { value: true })) })
.catch((error) => {
store.dispatch('pushGlobalNotice', {
level: 'error',
messageKey: 'timeline.error',
messageArgs: [error.message],
timeout: 5000
})
})
} }
const startFetching = ({ timeline = 'friends', credentials, store, userId = false, tag = false }) => { const startFetching = ({ timeline = 'friends', credentials, store, userId = false, tag = false }) => {

View file

@ -8,8 +8,7 @@ const localVue = createLocalVue()
localVue.use(Vuex) localVue.use(Vuex)
const mutations = { const mutations = {
clearTimeline: () => {}, clearTimeline: () => {}
setError: () => {}
} }
const actions = { const actions = {