From b6d3aeaf843fd657c5e9931158effa17d1b7a0fa Mon Sep 17 00:00:00 2001 From: AkiraFukushima Date: Fri, 15 Mar 2019 01:02:10 +0900 Subject: [PATCH 1/8] refs #843 Add Mention timeline --- src/config/locales/en/translation.json | 2 + src/main/index.js | 5 + .../TimelineSpace/Contents/Mentions.vue | 198 ++++++++++++++++++ .../TimelineSpace/Contents/Notifications.vue | 4 + .../components/TimelineSpace/HeaderMenu.vue | 12 ++ .../components/TimelineSpace/SideMenu.vue | 13 +- .../components/molecules/Notification.vue | 12 +- .../molecules/Notification/Mention.vue | 6 +- src/renderer/router/index.js | 5 + src/renderer/store/TimelineSpace.js | 9 + src/renderer/store/TimelineSpace/Contents.js | 2 + .../store/TimelineSpace/Contents/Mentions.js | 96 +++++++++ src/renderer/store/TimelineSpace/SideMenu.js | 5 + 13 files changed, 364 insertions(+), 5 deletions(-) create mode 100644 src/renderer/components/TimelineSpace/Contents/Mentions.vue create mode 100644 src/renderer/store/TimelineSpace/Contents/Mentions.js diff --git a/src/config/locales/en/translation.json b/src/config/locales/en/translation.json index 2e63297b..ebcf2f16 100644 --- a/src/config/locales/en/translation.json +++ b/src/config/locales/en/translation.json @@ -47,6 +47,7 @@ "expand": "Expand", "home": "Home", "notification": "Notification", + "mention": "Mention", "direct": "Direct messages", "favourite": "Favourite", "local": "Local timeline", @@ -58,6 +59,7 @@ "header_menu": { "home": "Home", "notification": "Notification", + "mention": "Mention", "favourite": "Favourite", "local": "Local timeline", "public": "Public timeline", diff --git a/src/main/index.js b/src/main/index.js index f47942cd..9204255d 100644 --- a/src/main/index.js +++ b/src/main/index.js @@ -413,6 +413,11 @@ ipcMain.on('start-user-streaming', (event, obj) => { }, (notification) => { event.sender.send('notification-start-user-streaming', notification) + // Does not exist a endpoint for only mention. And mention is a part of notification. + // So we have to get mention from notification. + if (notification.type === 'mention') { + event.sender.send('mention-start-user-streaming', notification) + } if (process.platform === 'darwin') { app.dock.setBadge('•') } diff --git a/src/renderer/components/TimelineSpace/Contents/Mentions.vue b/src/renderer/components/TimelineSpace/Contents/Mentions.vue new file mode 100644 index 00000000..8eb8b3b9 --- /dev/null +++ b/src/renderer/components/TimelineSpace/Contents/Mentions.vue @@ -0,0 +1,198 @@ + + + + + diff --git a/src/renderer/components/TimelineSpace/Contents/Notifications.vue b/src/renderer/components/TimelineSpace/Contents/Notifications.vue index ee38a023..9a84553c 100644 --- a/src/renderer/components/TimelineSpace/Contents/Notifications.vue +++ b/src/renderer/components/TimelineSpace/Contents/Notifications.vue @@ -10,6 +10,7 @@ :filter="filter" :focused="message.id === focusedId" :overlaid="modalOpened" + v-on:update="updateToot" @focusNext="focusNext" @focusPrev="focusPrev" @focusRight="focusSidebar" @@ -148,6 +149,9 @@ export default { this.$store.commit('TimelineSpace/changeLoading', false) } }, + updateToot (message) { + this.$store.commit('TimelineSpace/Contents/Notifications/updateToot', message) + }, upper () { scrollTop( document.getElementById('scrollable'), diff --git a/src/renderer/components/TimelineSpace/HeaderMenu.vue b/src/renderer/components/TimelineSpace/HeaderMenu.vue index 8efce734..fbfebd0d 100644 --- a/src/renderer/components/TimelineSpace/HeaderMenu.vue +++ b/src/renderer/components/TimelineSpace/HeaderMenu.vue @@ -103,6 +103,9 @@ export default { case 'favourites': this.$store.commit('TimelineSpace/HeaderMenu/updateTitle', this.$t('header_menu.favourite')) break + case 'mentions': + this.$store.commit('TimelineSpace/HeaderMenu/updateTitle', this.$t('header_menu.mention')) + break case 'local': this.$store.commit('TimelineSpace/HeaderMenu/updateTitle', this.$t('header_menu.local')) break @@ -148,6 +151,7 @@ export default { switch (this.$route.name) { case 'home': case 'notifications': + case 'mentions': case 'favourites': case 'local': case 'public': @@ -164,6 +168,7 @@ export default { switch (this.$route.name) { case 'home': case 'notifications': + case 'mentiont': case 'favourites': case 'local': case 'public': @@ -185,6 +190,9 @@ export default { case 'notifications': this.filter = this.$store.state.TimelineSpace.Contents.Notifications.filter break + case 'mentions': + this.filter = this.$store.state.TimelineSpace.Contents.Mentions.filter + break case 'favourites': this.filter = this.$store.state.TimelineSpace.Contents.Favourites.filter break @@ -217,6 +225,9 @@ export default { case 'notifications': this.$store.commit('TimelineSpace/Contents/Notifications/changeFilter', filter) break + case 'mentions': + this.$store.commit('TimelineSpace/Contents/Mentions/changeFilter', filter) + break case 'favourites': this.$store.commit('TimelineSpace/Contents/Favourites/changeFilter', filter) break @@ -244,6 +255,7 @@ export default { switch (this.$route.name) { case 'home': case 'notifications': + case 'mentions': case 'favourites': case 'local': case 'public': diff --git a/src/renderer/components/TimelineSpace/SideMenu.vue b/src/renderer/components/TimelineSpace/SideMenu.vue index 419faa8b..8a85cae6 100644 --- a/src/renderer/components/TimelineSpace/SideMenu.vue +++ b/src/renderer/components/TimelineSpace/SideMenu.vue @@ -52,9 +52,11 @@ - - - {{ $t("side_menu.favourite") }} + + + {{ $t("side_menu.mention") }} + + @@ -62,6 +64,10 @@ + + + {{ $t("side_menu.favourite") }} + {{ $t("side_menu.local") }} @@ -118,6 +124,7 @@ export default { ...mapState('TimelineSpace/SideMenu', { unreadHomeTimeline: state => state.unreadHomeTimeline, unreadNotifications: state => state.unreadNotifications, + unreadMentions: state => state.unreadMentions, unreadLocalTimeline: state => state.unreadLocalTimeline, unreadDirectMessagesTimeline: state => state.unreadDirectMessagesTimeline, unreadPublicTimeline: state => state.unreadPublicTimeline, diff --git a/src/renderer/components/molecules/Notification.vue b/src/renderer/components/molecules/Notification.vue index d13c7932..3855988e 100644 --- a/src/renderer/components/molecules/Notification.vue +++ b/src/renderer/components/molecules/Notification.vue @@ -26,6 +26,8 @@ :filter="filter" :focused="focused" :overlaid="overlaid" + v-on:update="updateToot" + v-on:delete="deleteToot" @focusNext="$emit('focusNext')" @focusPrev="$emit('focusPrev')" @focusRight="$emit('focusRight')" @@ -72,7 +74,15 @@ export default { default: false } }, - components: { Favourite, Follow, Mention, Reblog } + components: { Favourite, Follow, Mention, Reblog }, + methods: { + updateToot (message) { + return this.$emit('update', message) + }, + deleteToot (message) { + return this.$emit('delete', message) + } + } } diff --git a/src/renderer/components/molecules/Notification/Mention.vue b/src/renderer/components/molecules/Notification/Mention.vue index db0451d3..d0f1ccda 100644 --- a/src/renderer/components/molecules/Notification/Mention.vue +++ b/src/renderer/components/molecules/Notification/Mention.vue @@ -6,6 +6,7 @@ :focused="focused" :overlaid="overlaid" v-on:update="updateToot" + v-on:delete="deleteToot" @focusNext="$emit('focusNext')" @focusPrev="$emit('focusPrev')" @focusRight="$emit('focusRight')" @@ -41,7 +42,10 @@ export default { components: { Toot }, methods: { updateToot (message) { - this.$store.commit('TimelineSpace/Contents/Notifications/updateToot', message) + return this.$emit('update', message) + }, + deleteToot (message) { + return this.$emit('delete', message) } } } diff --git a/src/renderer/router/index.js b/src/renderer/router/index.js index c0e1e2a6..acb452ee 100644 --- a/src/renderer/router/index.js +++ b/src/renderer/router/index.js @@ -82,6 +82,11 @@ export default new Router({ name: 'notifications', component: require('@/components/TimelineSpace/Contents/Notifications').default }, + { + path: 'mentions', + name: 'mentions', + component: require('@/components/TimelineSpace/Contents/Mentions').default + }, { path: 'favourites', name: 'favourites', diff --git a/src/renderer/store/TimelineSpace.js b/src/renderer/store/TimelineSpace.js index 6abf622d..eec98351 100644 --- a/src/renderer/store/TimelineSpace.js +++ b/src/renderer/store/TimelineSpace.js @@ -189,6 +189,7 @@ const TimelineSpace = { async fetchContentsTimelines ({ dispatch, state }, account) { await dispatch('TimelineSpace/Contents/Home/fetchTimeline', account, { root: true }) await dispatch('TimelineSpace/Contents/Notifications/fetchNotifications', account, { root: true }) + await dispatch('TimelineSpace/Contents/Mentions/fetchMentions', {}, { root: true }) if (state.unreadNotification.direct) { await dispatch('TimelineSpace/Contents/DirectMessages/fetchTimeline', {}, { root: true }) } @@ -205,6 +206,7 @@ const TimelineSpace = { commit('TimelineSpace/Contents/DirectMessages/clearTimeline', {}, { root: true }) commit('TimelineSpace/Contents/Notifications/clearNotifications', {}, { root: true }) commit('TimelineSpace/Contents/Public/clearTimeline', {}, { root: true }) + commit('TimelineSpace/Contents/Mentions/clearMentions', {}, { root: true }) }, bindStreamings ({ dispatch, state }, account) { dispatch('bindUserStreaming', account) @@ -267,6 +269,13 @@ const TimelineSpace = { } commit('TimelineSpace/SideMenu/changeUnreadNotifications', true, { root: true }) }) + ipcRenderer.on('mention-start-user-streaming', (event, mention) => { + commit('TimelineSpace/Contents/Mentions/appendMentions', mention, { root: true }) + if (rootState.TimelineSpace.Contents.Mentions.heading && Math.random() > 0.8) { + commit('TimelineSpace/Contents/Mentions/archiveMentions', null, { root: true }) + } + commit('TimelineSpace/SideMenu/changeUnreadMentions', true, { root: true }) + }) }, startUserStreaming ({ state }) { return new Promise((resolve, reject) => { diff --git a/src/renderer/store/TimelineSpace/Contents.js b/src/renderer/store/TimelineSpace/Contents.js index d1758451..81b91d7a 100644 --- a/src/renderer/store/TimelineSpace/Contents.js +++ b/src/renderer/store/TimelineSpace/Contents.js @@ -8,6 +8,7 @@ import Search from './Contents/Search' import Lists from './Contents/Lists' import Hashtag from './Contents/Hashtag' import DirectMessages from './Contents/DirectMessages' +import Mentions from './Contents/Mentions' const Contents = { namespaced: true, @@ -18,6 +19,7 @@ const Contents = { Favourites, Local, DirectMessages, + Mentions, Public, Search, Lists, diff --git a/src/renderer/store/TimelineSpace/Contents/Mentions.js b/src/renderer/store/TimelineSpace/Contents/Mentions.js new file mode 100644 index 00000000..ef3111da --- /dev/null +++ b/src/renderer/store/TimelineSpace/Contents/Mentions.js @@ -0,0 +1,96 @@ +import Mastodon from 'megalodon' + +const Mentions = { + namespaced: true, + state: { + lazyLoading: false, + heading: true, + mentions: [], + unreadMentions: [], + filter: '' + }, + mutations: { + changeLazyLoading (state, value) { + state.lazyLoading = value + }, + changeHeading (state, value) { + state.heading = value + }, + appendMentions (state, update) { + if (state.heading) { + state.mentions = [update].concat(state.mentions) + } else { + state.unreadMentions = [update].concat(state.unreadMentions) + } + }, + updateMentions (state, messages) { + state.mentions = messages + }, + mergeMentions (state) { + state.mentions = state.unreadMentions.slice(0, 80).concat(state.mentions) + state.unreadMentions = [] + }, + insertMentions (state, messages) { + state.mentions = state.mentions.concat(messages) + }, + archiveMentions (state) { + state.mentions = state.mentions.slice(0, 40) + }, + clearMentions (state) { + state.mentions = [] + state.unreadMentions = [] + }, + updateToot (state, message) { + console.log(message) + state.mentions = state.mentions.map((mention) => { + if (mention.type === 'mention' && mention.status.id === message.id) { + const status = { + status: message + } + return Object.assign(mention, status) + } else { + return mention + } + }) + }, + changeFilter (state, filter) { + state.filter = filter + } + }, + actions: { + fetchMentions ({ state, commit, rootState }) { + const client = new Mastodon( + rootState.TimelineSpace.account.accessToken, + rootState.TimelineSpace.account.baseURL + '/api/v1' + ) + return client.get('/notifications', { limit: 30, exclude_types: ['follow', 'favourite', 'reblog'] }) + .then(res => { + commit('updateMentions', res.data) + return res.data + }) + }, + lazyFetchMentions ({ state, commit, rootState }, last) { + if (last === undefined || last === null) { + return Promise.resolve(null) + } + if (state.lazyLoading) { + return Promise.resolve(null) + } + commit('changeLazyLoading', true) + const client = new Mastodon( + rootState.TimelineSpace.account.accessToken, + rootState.TimelineSpace.account.baseURL + '/api/v1' + ) + return client.get('/notifications', { max_id: last.id, limit: 30, exclude_types: ['follow', 'favourite', 'reblog'] }) + .then(res => { + commit('insertMentions', res.data) + return res.data + }) + .finally(() => { + commit('changeLazyLoading', false) + }) + } + } +} + +export default Mentions diff --git a/src/renderer/store/TimelineSpace/SideMenu.js b/src/renderer/store/TimelineSpace/SideMenu.js index db72d8cc..1342db52 100644 --- a/src/renderer/store/TimelineSpace/SideMenu.js +++ b/src/renderer/store/TimelineSpace/SideMenu.js @@ -6,6 +6,7 @@ const SideMenu = { state: { unreadHomeTimeline: false, unreadNotifications: false, + unreadMentions: false, unreadLocalTimeline: false, unreadDirectMessagesTimeline: false, unreadPublicTimeline: false, @@ -20,6 +21,9 @@ const SideMenu = { changeUnreadNotifications (state, value) { state.unreadNotifications = value }, + changeUnreadMentions (state, value) { + state.unreadMentions = value + }, changeUnreadLocalTimeline (state, value) { state.unreadLocalTimeline = value }, @@ -55,6 +59,7 @@ const SideMenu = { clearUnread ({ commit }) { commit('changeUnreadHomeTimeline', false) commit('changeUnreadNotifications', false) + commit('changeUnreadMentions', false) commit('changeUnreadLocalTimeline', false) commit('changeUnreadDirectMessagesTimeline', false) commit('changeUnreadPublicTimeline', false) From f4ea67ff0a6e0f2d763c3012c879095ecf9df20e Mon Sep 17 00:00:00 2001 From: AkiraFukushima Date: Fri, 15 Mar 2019 01:04:37 +0900 Subject: [PATCH 2/8] refs #843 Fix reloadable for mentions --- src/renderer/components/TimelineSpace/HeaderMenu.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/renderer/components/TimelineSpace/HeaderMenu.vue b/src/renderer/components/TimelineSpace/HeaderMenu.vue index fbfebd0d..49c63ca6 100644 --- a/src/renderer/components/TimelineSpace/HeaderMenu.vue +++ b/src/renderer/components/TimelineSpace/HeaderMenu.vue @@ -168,7 +168,7 @@ export default { switch (this.$route.name) { case 'home': case 'notifications': - case 'mentiont': + case 'mentions': case 'favourites': case 'local': case 'public': From 0520b3406a10142a374cb832046cf35e42d8609a Mon Sep 17 00:00:00 2001 From: AkiraFukushima Date: Fri, 15 Mar 2019 01:12:37 +0900 Subject: [PATCH 3/8] refs #843 fix: Filter mentions to get only mentions for pleroma --- src/renderer/components/TimelineSpace/Contents/Mentions.vue | 4 +++- src/renderer/store/TimelineSpace/Contents/Mentions.js | 5 +++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/renderer/components/TimelineSpace/Contents/Mentions.vue b/src/renderer/components/TimelineSpace/Contents/Mentions.vue index 8eb8b3b9..d7fd7bda 100644 --- a/src/renderer/components/TimelineSpace/Contents/Mentions.vue +++ b/src/renderer/components/TimelineSpace/Contents/Mentions.vue @@ -55,7 +55,6 @@ export default { openSideBar: state => state.openSideBar }), ...mapState('TimelineSpace/Contents/Mentions', { - mentions: state => state.mentions, lazyLoading: state => state.lazyLoading, heading: state => state.heading, unread: state => state.unreadMentions, @@ -64,6 +63,9 @@ export default { ...mapGetters('TimelineSpace/Modals', [ 'modalOpened' ]), + ...mapGetters('TimelineSpace/Contents/Mentions', [ + 'mentions' + ]), shortcutEnabled: function () { if (this.modalOpened) { return false diff --git a/src/renderer/store/TimelineSpace/Contents/Mentions.js b/src/renderer/store/TimelineSpace/Contents/Mentions.js index ef3111da..9adac1a0 100644 --- a/src/renderer/store/TimelineSpace/Contents/Mentions.js +++ b/src/renderer/store/TimelineSpace/Contents/Mentions.js @@ -90,6 +90,11 @@ const Mentions = { commit('changeLazyLoading', false) }) } + }, + getters: { + mentions (state) { + return state.mentions.filter(mention => mention.type === 'mention') + } } } From 89ddb4c4d3f723f6f57a68a4eaeb9378c7303b68 Mon Sep 17 00:00:00 2001 From: AkiraFukushima Date: Fri, 15 Mar 2019 01:13:26 +0900 Subject: [PATCH 4/8] refs #843 Fix scroll design in Mentions --- .../TimelineSpace/Contents/Mentions.vue | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/renderer/components/TimelineSpace/Contents/Mentions.vue b/src/renderer/components/TimelineSpace/Contents/Mentions.vue index d7fd7bda..562f19e5 100644 --- a/src/renderer/components/TimelineSpace/Contents/Mentions.vue +++ b/src/renderer/components/TimelineSpace/Contents/Mentions.vue @@ -197,4 +197,40 @@ export default { + From dfd705b9d37cc9f4ff00b7eb0482cdde73e04cfb Mon Sep 17 00:00:00 2001 From: AkiraFukushima Date: Tue, 19 Mar 2019 09:07:13 +0900 Subject: [PATCH 5/8] refs #843 Add integration spec for mentions --- .../integration/store/TimelineSpace.spec.js | 10 +- .../store/TimelineSpace/Contents/Home.spec.js | 20 ++- .../TimelineSpace/Contents/Mentions.spec.js | 152 ++++++++++++++++++ 3 files changed, 180 insertions(+), 2 deletions(-) create mode 100644 spec/renderer/integration/store/TimelineSpace/Contents/Mentions.spec.js diff --git a/spec/renderer/integration/store/TimelineSpace.spec.js b/spec/renderer/integration/store/TimelineSpace.spec.js index 1180614d..9f3e0898 100644 --- a/spec/renderer/integration/store/TimelineSpace.spec.js +++ b/spec/renderer/integration/store/TimelineSpace.spec.js @@ -63,6 +63,13 @@ const PublicStore = { } } +const MentionStore = { + namespaced: true, + actions: { + fetchMentions: jest.fn() + } +} + const contentsStore = { namespaced: true, modules: { @@ -70,7 +77,8 @@ const contentsStore = { Notifications: notificationStore, DirectMessages: DMStore, Local: LocalStore, - Public: PublicStore + Public: PublicStore, + Mentions: MentionStore } } diff --git a/spec/renderer/integration/store/TimelineSpace/Contents/Home.spec.js b/spec/renderer/integration/store/TimelineSpace/Contents/Home.spec.js index adf9c6c7..59daba6f 100644 --- a/spec/renderer/integration/store/TimelineSpace/Contents/Home.spec.js +++ b/spec/renderer/integration/store/TimelineSpace/Contents/Home.spec.js @@ -6,7 +6,7 @@ import Home from '~/src/renderer/store/TimelineSpace/Contents/Home' jest.genMockFromModule('megalodon') jest.mock('megalodon') -const state = () => { +let state = () => { return { lazyLoading: false, heading: true, @@ -89,6 +89,22 @@ describe('Home', () => { }) }) describe('success', () => { + beforeAll(() => { + state = () => { + return { + lazyLoading: false, + heading: true, + timeline: [ + { id: 3 }, + { id: 4 } + ], + unreadTimeline: [], + filter: '', + showReblogs: true, + showReplies: true + } + } + }) it('should be updated', async () => { const mockClient = { get: () => { @@ -106,6 +122,8 @@ describe('Home', () => { await store.dispatch('Home/lazyFetchTimeline', { id: 20 }) expect(store.state.Home.lazyLoading).toEqual(false) expect(store.state.Home.timeline).toEqual([ + { id: 3 }, + { id: 4 }, { id: 19 }, { id: 18 } ]) diff --git a/spec/renderer/integration/store/TimelineSpace/Contents/Mentions.spec.js b/spec/renderer/integration/store/TimelineSpace/Contents/Mentions.spec.js new file mode 100644 index 00000000..905c4e31 --- /dev/null +++ b/spec/renderer/integration/store/TimelineSpace/Contents/Mentions.spec.js @@ -0,0 +1,152 @@ +import Mastodon from 'megalodon' +import { createLocalVue } from '@vue/test-utils' +import Vuex from 'vuex' +import Mentions from '~/src/renderer/store/TimelineSpace/Contents/Mentions' + +jest.genMockFromModule('megalodon') +jest.mock('megalodon') + +let state = () => { + return { + lazyLoading: false, + heading: true, + mentions: [], + unreadMentions: [], + filter: '' + } +} + +const initStore =() => { + return { + namespaced: true, + state: state(), + actions: Mentions.actions, + mutations: Mentions.mutations + } +} +const timelineState = { + namespaced: true, + state: { + account: { + accessToken: 'token', + baseURL: 'http://localhost' + } + } +} + +describe('Mentions', () => { + let store + let localVue + + beforeEach(() => { + localVue = createLocalVue() + localVue.use(Vuex) + store = new Vuex.Store({ + modules: { + Mentions: initStore(), + TimelineSpace: timelineState + } + }) + Mastodon.mockClear() + }) + + describe('fetchMentions', () => { + it('should be updated', async () => { + const mockClient = { + get: () => { + return new Promise((resolve, reject) => { + resolve({ + data: [ + { id: 1, type: 'mention' }, + { id: 2, type: 'favourite' }, + { id: 3, type: 'reblog' }, + { id: 4, type: 'follow' } + ] + }) + }) + } + } + + Mastodon.mockImplementation(() => mockClient) + const mentions = await store.dispatch('Mentions/fetchMentions') + expect(store.state.Mentions.mentions).toEqual([ + { id: 1, type: 'mention' }, + { id: 2, type: 'favourite' }, + { id: 3, type: 'reblog' }, + { id: 4, type: 'follow' } + ]) + }) + }) + + describe('lazyFetchMentions', () => { + describe('last is null', () => { + it('should not be updated', async () => { + const result = await store.dispatch('Mentions/lazyFetchMentions', null) + expect(result).toEqual(null) + }) + }) + + describe('loading', () => { + beforeAll(() => { + state = () => { + return { + lazyLoading: true, + heading: true, + mentions: [], + unreadMentions: [], + filter: '' + } + } + }) + it('should not be updated', async () => { + const result = await store.dispatch('Mentions/lazyFetchMentions', {}) + expect(result).toEqual(null) + }) + }) + + describe('success', () => { + beforeAll(() => { + state = () => { + return { + lazyLoading: false, + heading: true, + mentions: [ + { id: 1, type: 'mention' }, + { id: 2, type: 'favourite' }, + { id: 3, type: 'reblog' }, + { id: 4, type: 'follow' } + ], + unreadMentions: [], + filter: '' + } + } + }) + it('should be updated', async () => { + const mockClient = { + get: () => { + return new Promise((resolve, reject) => { + resolve({ + data: [ + { id: 5, type: 'mention' }, + { id: 6, type: 'favourite' } + ] + }) + }) + } + } + + Mastodon.mockImplementation(() => mockClient) + const mentions = await store.dispatch('Mentions/lazyFetchMentions', { id: 1 }) + expect(store.state.Mentions.mentions).toEqual([ + { id: 1, type: 'mention' }, + { id: 2, type: 'favourite' }, + { id: 3, type: 'reblog' }, + { id: 4, type: 'follow' }, + { id: 5, type: 'mention' }, + { id: 6, type: 'favourite' } + ]) + expect(store.state.Mentions.lazyLoading).toEqual(false) + }) + }) + }) +}) From 68114b86f3056d76cb5641584f6faf48684c909d Mon Sep 17 00:00:00 2001 From: AkiraFukushima Date: Tue, 19 Mar 2019 09:24:07 +0900 Subject: [PATCH 6/8] refs #843 Add unit spec for mentions --- .../TimelineSpace/Contents/Mentions.spec.js | 114 ++++++++++++++++++ .../store/TimelineSpace/Contents/Mentions.js | 1 - 2 files changed, 114 insertions(+), 1 deletion(-) create mode 100644 spec/renderer/unit/store/TimelineSpace/Contents/Mentions.spec.js diff --git a/spec/renderer/unit/store/TimelineSpace/Contents/Mentions.spec.js b/spec/renderer/unit/store/TimelineSpace/Contents/Mentions.spec.js new file mode 100644 index 00000000..f791c518 --- /dev/null +++ b/spec/renderer/unit/store/TimelineSpace/Contents/Mentions.spec.js @@ -0,0 +1,114 @@ +import Mentions from '@/store/TimelineSpace/Contents/Mentions' + +describe('TimelineSpace/Contents/Mentions', () => { + describe('mutations', () => { + let state + beforeEach(() => { + state = { + lazyLoading: false, + heading: true, + mentions: [], + unreadMentions: [], + filter: '' + } + }) + + describe('appendMentions', () => { + describe('heading', () => { + beforeEach(() => { + state = { + lazyLoading: false, + heading: true, + mentions: [5, 4, 3, 2, 1], + unreadMentions: [], + filter: '' + } + }) + it('should update mentions', () => { + Mentions.mutations.appendMentions(state, 6) + expect(state.mentions).toEqual([6, 5, 4, 3, 2, 1]) + expect(state.unreadMentions).toEqual([]) + }) + }) + describe('not heading', () => { + beforeEach(() => { + state = { + lazyLoading: false, + heading: false, + mentions: [5, 4, 3, 2, 1], + unreadMentions: [], + filter: '' + } + }) + it('should update mentions', () => { + Mentions.mutations.appendMentions(state, 6) + expect(state.mentions).toEqual([5, 4, 3, 2, 1]) + expect(state.unreadMentions).toEqual([6]) + }) + }) + }) + + describe('mergeMentions', () => { + beforeEach(() => { + state = { + lazyLoading: false, + heading: false, + mentions: [5, 4, 3, 2, 1], + unreadMentions: [8, 7, 6], + filter: '' + } + }) + it('should be merged', () => { + Mentions.mutations.mergeMentions(state) + expect(state.mentions).toEqual([8, 7, 6, 5, 4, 3, 2, 1]) + expect(state.unreadMentions).toEqual([]) + }) + }) + + describe('insertMentions', () => { + beforeEach(() => { + state = { + lazyLoading: false, + heading: false, + mentions: [5, 4, 3, 2, 1], + unreadMentions: [], + filter: '' + } + }) + it('should be inserted', () => { + Mentions.mutations.insertMentions(state, [ -1, -2, -3, -4]) + expect(state.mentions).toEqual([5, 4, 3, 2, 1, -1, -2, -3, -4]) + }) + }) + + describe('updateToot', () => { + beforeEach(() => { + state = { + lazyLoading: false, + heading: false, + mentions: [ + { type: 'mention', status: { id: 20, favourited: false } }, + { type: 'favourite', status: { id: 19, favourited: false } }, + { type: 'reblog', status: { id: 18, favourited: false } }, + { type: 'follow', status: { id: 17, favourited: false } }, + { type: 'mention', status: { id: 16, favourited: false } } + ], + unreadMentions: [], + filter: '' + } + }) + it('should be updated', () => { + Mentions.mutations.updateToot(state, { id: 20, favourited: true }) + expect(state.mentions).toEqual( + [ + { type: 'mention', status: { id: 20, favourited: true } }, + { type: 'favourite', status: { id: 19, favourited: false } }, + { type: 'reblog', status: { id: 18, favourited: false } }, + { type: 'follow', status: { id: 17, favourited: false } }, + { type: 'mention', status: { id: 16, favourited: false } } + ] + ) + }) + }) + }) +}) diff --git a/src/renderer/store/TimelineSpace/Contents/Mentions.js b/src/renderer/store/TimelineSpace/Contents/Mentions.js index 9adac1a0..b945928f 100644 --- a/src/renderer/store/TimelineSpace/Contents/Mentions.js +++ b/src/renderer/store/TimelineSpace/Contents/Mentions.js @@ -41,7 +41,6 @@ const Mentions = { state.unreadMentions = [] }, updateToot (state, message) { - console.log(message) state.mentions = state.mentions.map((mention) => { if (mention.type === 'mention' && mention.status.id === message.id) { const status = { From efc41b283bbd351b3798ffeab8e341429e06a625 Mon Sep 17 00:00:00 2001 From: AkiraFukushima Date: Tue, 19 Mar 2019 09:27:01 +0900 Subject: [PATCH 7/8] refs #843 Add getters spec for mentions --- .../TimelineSpace/Contents/Mentions.spec.js | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/spec/renderer/integration/store/TimelineSpace/Contents/Mentions.spec.js b/spec/renderer/integration/store/TimelineSpace/Contents/Mentions.spec.js index 905c4e31..64fd82ad 100644 --- a/spec/renderer/integration/store/TimelineSpace/Contents/Mentions.spec.js +++ b/spec/renderer/integration/store/TimelineSpace/Contents/Mentions.spec.js @@ -21,7 +21,8 @@ const initStore =() => { namespaced: true, state: state(), actions: Mentions.actions, - mutations: Mentions.mutations + mutations: Mentions.mutations, + getters: Mentions.getters } } const timelineState = { @@ -149,4 +150,29 @@ describe('Mentions', () => { }) }) }) + + describe('mentions', () => { + beforeAll(() => { + state = () => { + return { + lazyLoading: false, + heading: true, + mentions: [ + { id: 1, type: 'mention' }, + { id: 2, type: 'favourite' }, + { id: 3, type: 'reblog' }, + { id: 4, type: 'follow' } + ], + unreadMentions: [], + filter: '' + } + } + }) + it('should return only mentions', () => { + const mentions = store.getters['Mentions/mentions'] + expect(mentions).toEqual([ + { id: 1, type: 'mention' } + ]) + }) + }) }) From 8414e22b966a24cfe74b3c3f3b0ffd09cdcbccb4 Mon Sep 17 00:00:00 2001 From: AkiraFukushima Date: Tue, 19 Mar 2019 09:29:25 +0900 Subject: [PATCH 8/8] refs #843 Fix code style for mentions --- .../store/TimelineSpace/Contents/Mentions.spec.js | 8 ++++---- .../unit/store/TimelineSpace/Contents/Mentions.spec.js | 2 +- .../components/TimelineSpace/Contents/Mentions.vue | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/spec/renderer/integration/store/TimelineSpace/Contents/Mentions.spec.js b/spec/renderer/integration/store/TimelineSpace/Contents/Mentions.spec.js index 64fd82ad..843561d2 100644 --- a/spec/renderer/integration/store/TimelineSpace/Contents/Mentions.spec.js +++ b/spec/renderer/integration/store/TimelineSpace/Contents/Mentions.spec.js @@ -16,7 +16,7 @@ let state = () => { } } -const initStore =() => { +const initStore = () => { return { namespaced: true, state: state(), @@ -69,7 +69,7 @@ describe('Mentions', () => { } Mastodon.mockImplementation(() => mockClient) - const mentions = await store.dispatch('Mentions/fetchMentions') + await store.dispatch('Mentions/fetchMentions') expect(store.state.Mentions.mentions).toEqual([ { id: 1, type: 'mention' }, { id: 2, type: 'favourite' }, @@ -80,7 +80,7 @@ describe('Mentions', () => { }) describe('lazyFetchMentions', () => { - describe('last is null', () => { + describe('last is null', () => { it('should not be updated', async () => { const result = await store.dispatch('Mentions/lazyFetchMentions', null) expect(result).toEqual(null) @@ -137,7 +137,7 @@ describe('Mentions', () => { } Mastodon.mockImplementation(() => mockClient) - const mentions = await store.dispatch('Mentions/lazyFetchMentions', { id: 1 }) + await store.dispatch('Mentions/lazyFetchMentions', { id: 1 }) expect(store.state.Mentions.mentions).toEqual([ { id: 1, type: 'mention' }, { id: 2, type: 'favourite' }, diff --git a/spec/renderer/unit/store/TimelineSpace/Contents/Mentions.spec.js b/spec/renderer/unit/store/TimelineSpace/Contents/Mentions.spec.js index f791c518..69ad0e56 100644 --- a/spec/renderer/unit/store/TimelineSpace/Contents/Mentions.spec.js +++ b/spec/renderer/unit/store/TimelineSpace/Contents/Mentions.spec.js @@ -76,7 +76,7 @@ describe('TimelineSpace/Contents/Mentions', () => { } }) it('should be inserted', () => { - Mentions.mutations.insertMentions(state, [ -1, -2, -3, -4]) + Mentions.mutations.insertMentions(state, [-1, -2, -3, -4]) expect(state.mentions).toEqual([5, 4, 3, 2, 1, -1, -2, -3, -4]) }) }) diff --git a/src/renderer/components/TimelineSpace/Contents/Mentions.vue b/src/renderer/components/TimelineSpace/Contents/Mentions.vue index 562f19e5..3951f958 100644 --- a/src/renderer/components/TimelineSpace/Contents/Mentions.vue +++ b/src/renderer/components/TimelineSpace/Contents/Mentions.vue @@ -203,7 +203,7 @@ export default { right: 24px; top: 48px; background-color: rgba(0, 0, 0, 0.7); - color: #ffffff; + color: #fff; padding: 4px 8px; border-radius: 0 0 2px 2px;