Merge branch '549' into 'develop'

Prevent showing pinned statuses twice

Closes 

See merge request 
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
src
components
modules
services/entity_normalizer
test/unit/specs/components

View file

@ -1,7 +1,20 @@
import Status from '../status/status.vue'
import timelineFetcher from '../../services/timeline_fetcher/timeline_fetcher.service.js'
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 = {
props: [
@ -11,7 +24,8 @@ const Timeline = {
'userId',
'tag',
'embedded',
'count'
'count',
'pinnedStatusIds'
],
data () {
return {
@ -39,6 +53,12 @@ const Timeline = {
body: ['timeline-body'].concat(!this.embedded ? ['panel-body'] : []),
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: {

View file

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

View file

@ -15,25 +15,14 @@
:render-only-focused="true"
>
<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
:count="user.statuses_count"
:embedded="true"
:title="$t('user_profile.timeline_title')"
:timeline="timeline"
:timeline-name="'user'"
timeline-name="user"
:user-id="userId"
:pinned-status-ids="user.pinnedStatusIds"
/>
</div>
<div

View file

@ -167,11 +167,11 @@ export const mutations = {
},
setPinned (state, status) {
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) {
user.pinnedStatuseIds.push(status.id)
user.pinnedStatusIds.push(status.id)
} else if (!status.pinned && index !== -1) {
user.pinnedStatuseIds.splice(index, 1)
user.pinnedStatusIds.splice(index, 1)
}
},
setUserForStatus (state, status) {

View file

@ -152,7 +152,7 @@ export const parseUser = (data) => {
output.statuses_count = data.statuses_count
output.friendIds = []
output.followerIds = []
output.pinnedStatuseIds = []
output.pinnedStatusIds = []
if (data.pleroma) {
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)
})
})
})