logo

pleroma-fe

My custom branche(s) on git.pleroma.social/pleroma/pleroma-fe
commit: 8aa3e7d52ea067c12dd12c711121fda190b5979d
parent: 4827e4d972f8ee11e606693e24ae4ca21711c6b1
Author: HJ <30-hj@users.noreply.git.pleroma.social>
Date:   Sun, 28 Jul 2019 21:05:22 +0000

Merge branch '549' into 'develop'

Prevent showing pinned statuses twice

Closes #549

See merge request pleroma/pleroma-fe!812

Diffstat:

Msrc/components/timeline/timeline.js24++++++++++++++++++++++--
Msrc/components/timeline/timeline.vue26+++++++++++++++++++-------
Msrc/components/user_profile/user_profile.vue15++-------------
Msrc/modules/users.js6+++---
Msrc/services/entity_normalizer/entity_normalizer.service.js2+-
Atest/unit/specs/components/timeline.spec.js27+++++++++++++++++++++++++++
6 files changed, 74 insertions(+), 26 deletions(-)

diff --git a/src/components/timeline/timeline.js b/src/components/timeline/timeline.js @@ -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: { diff --git a/src/components/timeline/timeline.vue b/src/components/timeline/timeline.vue @@ -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"> diff --git a/src/components/user_profile/user_profile.vue b/src/components/user_profile/user_profile.vue @@ -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 diff --git a/src/modules/users.js b/src/modules/users.js @@ -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) { diff --git a/src/services/entity_normalizer/entity_normalizer.service.js b/src/services/entity_normalizer/entity_normalizer.service.js @@ -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 diff --git a/test/unit/specs/components/timeline.spec.js b/test/unit/specs/components/timeline.spec.js @@ -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) + }) + }) +})