Skip to content

Commit 358ea29

Browse files
committed
fixup! assign a leader tab to fetch conversations and update talk-hash every 30 seconds only from one source
Signed-off-by: Maksim Sukharev <antreesy.web@gmail.com>
1 parent 8a94079 commit 358ea29

5 files changed

Lines changed: 65 additions & 51 deletions

File tree

src/App.vue

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ import Router from './router/router.js'
6464
import BrowserStorage from './services/BrowserStorage.js'
6565
import { EventBus } from './services/EventBus.js'
6666
import { leaveConversationSync } from './services/participantsService.js'
67+
import { useLeaderTabStore } from './stores/leaderTab.js'
6768
import { signalingKill } from './utils/webrtc/index.js'
6869
6970
// Styles
@@ -94,7 +95,12 @@ export default {
9495
9596
setup() {
9697
const isInCall = useIsInCall()
97-
return { isInCall }
98+
const leaderTabStore = useLeaderTabStore()
99+
100+
return {
101+
isInCall,
102+
leaderTabStore,
103+
}
98104
},
99105
100106
data() {
@@ -209,8 +215,8 @@ export default {
209215
return OCP.Accessibility.disableKeyboardShortcuts()
210216
},
211217
212-
isLeaderTab() {
213-
return this.$store.getters.isCurrentTabLeader
218+
isCurrentTabLeader() {
219+
return this.leaderTabStore.isCurrentTabLeader
214220
},
215221
},
216222
@@ -449,10 +455,10 @@ export default {
449455
console.debug('Can not set current user because it\'s a guest')
450456
}
451457
452-
this.$store.dispatch('requestTabLeadership')
458+
this.leaderTabStore.requestTabLeadership()
453459
454460
talkBroadcastChannel.onmessage = (event) => {
455-
if (this.isLeaderTab) {
461+
if (this.isCurrentTabLeader) {
456462
return
457463
}
458464

src/components/LeftSidebar/LeftSidebar.spec.js

Lines changed: 9 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { createLocalVue, mount } from '@vue/test-utils'
22
import flushPromises from 'flush-promises' // TODO fix after migration to @vue/test-utils v2.0.0
33
import { cloneDeep } from 'lodash'
4+
import { createPinia, setActivePinia } from 'pinia'
45
import VueRouter from 'vue-router'
56
import Vuex from 'vuex'
67

@@ -13,6 +14,7 @@ import router from '../../__mocks__/router.js'
1314
import { searchPossibleConversations, searchListedConversations } from '../../services/conversationsService.js'
1415
import { EventBus } from '../../services/EventBus.js'
1516
import storeConfig from '../../store/storeConfig.js'
17+
import { useLeaderTabStore } from '../../stores/leaderTab.js'
1618
import { findNcListItems, findNcActionButton } from '../../test-helpers.js'
1719

1820
jest.mock('@nextcloud/initial-state', () => ({
@@ -32,7 +34,6 @@ describe('LeftSidebar.vue', () => {
3234
let testStoreConfig
3335
let loadStateSettings
3436
let conversationsListMock
35-
let isLeaderTabMock
3637
let fetchConversationsAction
3738
let addConversationAction
3839
let createOneToOneConversationAction
@@ -54,7 +55,7 @@ describe('LeftSidebar.vue', () => {
5455
})
5556
}
5657

57-
beforeEach(() => {
58+
beforeEach(async () => {
5859
jest.useFakeTimers()
5960

6061
localVue = createLocalVue()
@@ -77,19 +78,23 @@ describe('LeftSidebar.vue', () => {
7778

7879
// note: need a copy because the Vue modifies it when sorting
7980
conversationsListMock = jest.fn()
80-
isLeaderTabMock = jest.fn()
8181
fetchConversationsAction = jest.fn().mockReturnValue({ headers: {} })
8282
addConversationAction = jest.fn()
8383
createOneToOneConversationAction = jest.fn()
8484
const getUserIdMock = jest.fn().mockReturnValue('current-user')
8585
testStoreConfig.modules.actorStore.getters.getUserId = () => getUserIdMock
86-
testStoreConfig.modules.talkHashStore.getters.isCurrentTabLeader = isLeaderTabMock
8786
testStoreConfig.modules.conversationsStore.getters.conversationsList = conversationsListMock
8887
testStoreConfig.modules.conversationsStore.actions.fetchConversations = fetchConversationsAction
8988
testStoreConfig.modules.conversationsStore.actions.addConversation = addConversationAction
9089
testStoreConfig.modules.conversationsStore.actions.createOneToOneConversation = createOneToOneConversationAction
9190

9291
store = new Vuex.Store(testStoreConfig)
92+
93+
setActivePinia(createPinia())
94+
const leaderTabStore = useLeaderTabStore()
95+
await leaderTabStore.requestTabLeadership()
96+
97+
// TODO add a unit test for sub-tabs
9398
})
9499

95100
afterEach(() => {
@@ -125,7 +130,6 @@ describe('LeftSidebar.vue', () => {
125130

126131
// note: need a copy because the Vue modifies it when sorting
127132
conversationsListMock.mockImplementation(() => cloneDeep(conversationsList))
128-
isLeaderTabMock.mockReturnValue(true)
129133
})
130134

131135
test('fetches and renders conversation list initially', async () => {
@@ -193,22 +197,6 @@ describe('LeftSidebar.vue', () => {
193197
// note: debounce was short-circuited so no delay needed
194198
expect(fetchConversationsAction).toHaveBeenCalled()
195199
})
196-
197-
test('doesn\'t fetch conversations if not a leader tab', async () => {
198-
isLeaderTabMock.mockReturnValue(false)
199-
const wrapper = mountComponent()
200-
expect(wrapper.exists()).toBeTruthy()
201-
expect(fetchConversationsAction).not.toHaveBeenCalled()
202-
203-
fetchConversationsAction.mockClear()
204-
205-
// move past async call
206-
await flushPromises()
207-
expect(fetchConversationsAction).not.toHaveBeenCalled()
208-
209-
jest.advanceTimersByTime(30000)
210-
expect(fetchConversationsAction).not.toHaveBeenCalled()
211-
})
212200
})
213201

214202
describe('search results', () => {
@@ -293,7 +281,6 @@ describe('LeftSidebar.vue', () => {
293281
// note: need a copy because the Vue modifies it when sorting
294282
conversationsListMock.mockImplementation(() => cloneDeep(conversationsList))
295283
fetchConversationsAction.mockResolvedValue()
296-
isLeaderTabMock.mockReturnValue(true)
297284
})
298285

299286
/**

src/components/LeftSidebar/LeftSidebar.vue

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,7 @@ import {
261261
searchListedConversations,
262262
} from '../../services/conversationsService.js'
263263
import { EventBus } from '../../services/EventBus.js'
264+
import { useLeaderTabStore } from '../../stores/leaderTab.js'
264265
import CancelableRequest from '../../utils/cancelableRequest.js'
265266
266267
export default {
@@ -300,11 +301,13 @@ export default {
300301
const searchBox = ref(null)
301302
302303
const { initializeNavigation } = useArrowNavigation(leftSidebar, searchBox)
304+
const leaderTabStore = useLeaderTabStore()
303305
304306
return {
305307
initializeNavigation,
306308
leftSidebar,
307309
searchBox,
310+
leaderTabStore,
308311
}
309312
},
310313
@@ -404,13 +407,13 @@ export default {
404407
}
405408
},
406409
407-
isLeaderTab() {
408-
return this.$store.getters.isCurrentTabLeader
410+
isCurrentTabLeader() {
411+
return this.leaderTabStore.isCurrentTabLeader
409412
},
410413
},
411414
412415
watch: {
413-
isLeaderTab: {
416+
isCurrentTabLeader: {
414417
immediate: true,
415418
handler(value) {
416419
if (!value) {

src/store/talkHashStore.js

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -22,24 +22,18 @@
2222

2323
import { showError, TOAST_PERMANENT_TIMEOUT } from '@nextcloud/dialogs'
2424

25-
import { onTalkLeaderTab } from '../utils/talkLeader.js'
26-
2725
const talkBroadcastChannel = new BroadcastChannel('nextcloud:talk')
2826

2927
const state = {
3028
initialNextcloudTalkHash: '',
3129
isNextcloudTalkHashDirty: false,
3230
maintenanceWarningToast: null,
33-
isCurrentTabLeader: false,
3431
}
3532

3633
const getters = {
3734
isNextcloudTalkHashDirty: (state) => {
3835
return state.isNextcloudTalkHashDirty
3936
},
40-
isCurrentTabLeader: (state) => {
41-
return state.isCurrentTabLeader
42-
},
4337
}
4438

4539
const mutations = {
@@ -71,15 +65,6 @@ const mutations = {
7165
setMaintenanceWarningToast(state, maintenanceWarningToast) {
7266
state.maintenanceWarningToast = maintenanceWarningToast
7367
},
74-
75-
/**
76-
* Mark the current Tab as a leader
77-
*
78-
* @param {object} state current store state
79-
*/
80-
setCurrentTabLeader: (state) => {
81-
state.isCurrentTabLeader = true
82-
},
8368
}
8469

8570
const actions = {
@@ -132,12 +117,6 @@ const actions = {
132117
context.commit('setMaintenanceWarningToast', null)
133118
}
134119
},
135-
136-
requestTabLeadership(context) {
137-
onTalkLeaderTab().then(() => {
138-
context.commit('setCurrentTabLeader')
139-
})
140-
},
141120
}
142121

143122
export default { state, mutations, getters, actions }

src/stores/leaderTab.js

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/**
2+
* @copyright Copyright (c) 2023 Maksim Sukharev <antreesy.web@gmail.com>
3+
*
4+
* @author Maksim Sukharev <antreesy.web@gmail.com>
5+
*
6+
* @license AGPL-3.0-or-later
7+
*
8+
* This program is free software: you can redistribute it and/or modify
9+
* it under the terms of the GNU Affero General Public License as
10+
* published by the Free Software Foundation, either version 3 of the
11+
* License, or (at your option) any later version.
12+
*
13+
* This program is distributed in the hope that it will be useful,
14+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16+
* GNU Affero General Public License for more details.
17+
*
18+
* You should have received a copy of the GNU Affero General Public License
19+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
20+
*
21+
*/
22+
23+
import { defineStore } from 'pinia'
24+
import Vue from 'vue'
25+
26+
import { onTalkLeaderTab } from '../utils/talkLeader.js'
27+
28+
export const useLeaderTabStore = defineStore('leaderTab', {
29+
state: () => ({
30+
isCurrentTabLeader: false,
31+
}),
32+
33+
actions: {
34+
async requestTabLeadership() {
35+
await onTalkLeaderTab()
36+
Vue.set(this, 'isCurrentTabLeader', true)
37+
},
38+
},
39+
})

0 commit comments

Comments
 (0)