Merge branch '549' into 'develop'

Prevent showing pinned statuses twice

Closes #549

See merge request pleroma/pleroma-fe!812
This commit is contained in:
HJ 2019-07-28 21:05:22 +00:00
commit 8aa3e7d52e
6 changed files with 74 additions and 26 deletions

View file

@ -1,7 +1,20 @@
import Status from '../status/status.vue' import Status from '../status/status.vue'
import timelineFetcher from '../../services/timeline_fetcher/timeline_fetcher.service.js' import timelineFetcher from '../../services/timeline_fetcher/timeline_fetcher.service.js'
import Conversation from '../conversation/conversation.vue' import Conversation from '../conversation/conversation.vue'
import { throttle } from 'lodash' import { throttle, keyBy } from 'lodash'
export const getExcludedStatusIdsByPinning = (statuses, pinnedStatusIds) => {
const ids = []
if (pinnedStatusIds && pinnedStatusIds.length > 0) {
for (let status of statuses) {
if (!pinnedStatusIds.includes(status.id)) {
break
}
ids.push(status.id)
}
}
return ids
}
const Timeline = { const Timeline = {
props: [ props: [
@ -11,7 +24,8 @@ const Timeline = {
'userId', 'userId',
'tag', 'tag',
'embedded', 'embedded',
'count' 'count',
'pinnedStatusIds'
], ],
data () { data () {
return { return {
@ -39,6 +53,12 @@ const Timeline = {
body: ['timeline-body'].concat(!this.embedded ? ['panel-body'] : []), body: ['timeline-body'].concat(!this.embedded ? ['panel-body'] : []),
footer: ['timeline-footer'].concat(!this.embedded ? ['panel-footer'] : []) footer: ['timeline-footer'].concat(!this.embedded ? ['panel-footer'] : [])
} }
},
// id map of statuses which need to be hidden in the main list due to pinning logic
excludedStatusIdsObject () {
const ids = getExcludedStatusIdsByPinning(this.timeline.visibleStatuses, this.pinnedStatusIds)
// Convert id array to object
return keyBy(ids, id => id)
} }
}, },
components: { components: {

View file

@ -28,13 +28,25 @@
</div> </div>
<div :class="classes.body"> <div :class="classes.body">
<div class="timeline"> <div class="timeline">
<conversation <template v-for="statusId in pinnedStatusIds">
v-for="status in timeline.visibleStatuses" <conversation
:key="status.id" v-if="timeline.statusesObject[statusId]"
class="status-fadein" :key="statusId + '-pinned'"
:statusoid="status" class="status-fadein"
:collapsable="true" :statusoid="timeline.statusesObject[statusId]"
/> :collapsable="true"
:show-pinned="true"
/>
</template>
<template v-for="status in timeline.visibleStatuses">
<conversation
v-if="!excludedStatusIdsObject[status.id]"
:key="status.id"
class="status-fadein"
:statusoid="status"
:collapsable="true"
/>
</template>
</div> </div>
</div> </div>
<div :class="classes.footer"> <div :class="classes.footer">

View file

@ -15,25 +15,14 @@
:render-only-focused="true" :render-only-focused="true"
> >
<div :label="$t('user_card.statuses')"> <div :label="$t('user_card.statuses')">
<div class="timeline">
<template v-for="statusId in user.pinnedStatuseIds">
<Conversation
v-if="timeline.statusesObject[statusId]"
:key="statusId"
class="status-fadein"
:statusoid="timeline.statusesObject[statusId]"
:collapsable="true"
:show-pinned="true"
/>
</template>
</div>
<Timeline <Timeline
:count="user.statuses_count" :count="user.statuses_count"
:embedded="true" :embedded="true"
:title="$t('user_profile.timeline_title')" :title="$t('user_profile.timeline_title')"
:timeline="timeline" :timeline="timeline"
:timeline-name="'user'" timeline-name="user"
:user-id="userId" :user-id="userId"
:pinned-status-ids="user.pinnedStatusIds"
/> />
</div> </div>
<div <div

View file

@ -167,11 +167,11 @@ export const mutations = {
}, },
setPinned (state, status) { setPinned (state, status) {
const user = state.usersObject[status.user.id] const user = state.usersObject[status.user.id]
const index = user.pinnedStatuseIds.indexOf(status.id) const index = user.pinnedStatusIds.indexOf(status.id)
if (status.pinned && index === -1) { if (status.pinned && index === -1) {
user.pinnedStatuseIds.push(status.id) user.pinnedStatusIds.push(status.id)
} else if (!status.pinned && index !== -1) { } else if (!status.pinned && index !== -1) {
user.pinnedStatuseIds.splice(index, 1) user.pinnedStatusIds.splice(index, 1)
} }
}, },
setUserForStatus (state, status) { setUserForStatus (state, status) {

View file

@ -152,7 +152,7 @@ export const parseUser = (data) => {
output.statuses_count = data.statuses_count output.statuses_count = data.statuses_count
output.friendIds = [] output.friendIds = []
output.followerIds = [] output.followerIds = []
output.pinnedStatuseIds = [] output.pinnedStatusIds = []
if (data.pleroma) { if (data.pleroma) {
output.follow_request_count = data.pleroma.follow_request_count output.follow_request_count = data.pleroma.follow_request_count

View file

@ -0,0 +1,27 @@
import { getExcludedStatusIdsByPinning } from 'src/components/timeline/timeline.js'
describe('Timeline', () => {
describe('getExcludedStatusIdsByPinning', () => {
const mockStatuses = (ids) => ids.map(id => ({ id }))
it('should return only members of both pinnedStatusIds and ids of the given statuses', () => {
const statusIds = [1, 2, 3, 4]
const statuses = mockStatuses(statusIds)
const pinnedStatusIds = [1, 3, 5]
const result = getExcludedStatusIdsByPinning(statuses, pinnedStatusIds)
result.forEach(item => {
expect(item).to.be.oneOf(statusIds)
expect(item).to.be.oneOf(pinnedStatusIds)
})
})
it('should return ids of pinned statuses not posted before any unpinned status', () => {
const pinnedStatusIdSet1 = ['PINNED1', 'PINNED2']
const pinnedStatusIdSet2 = ['PINNED3', 'PINNED4']
const pinnedStatusIds = [...pinnedStatusIdSet1, ...pinnedStatusIdSet2]
const statusIds = [...pinnedStatusIdSet1, 'UNPINNED1', ...pinnedStatusIdSet2]
const statuses = mockStatuses(statusIds)
expect(getExcludedStatusIdsByPinning(statuses, pinnedStatusIds)).to.eql(pinnedStatusIdSet1)
})
})
})