diff options
-rw-r--r-- | .github/workflows/appstore-build-publish.yml | 42 | ||||
-rw-r--r-- | CHANGELOG.md | 40 | ||||
-rw-r--r-- | Makefile | 5 | ||||
-rw-r--r-- | appinfo/info.xml | 2 | ||||
-rw-r--r-- | docs/Talkbuchet.js | 162 | ||||
-rw-r--r-- | docs/reaction.md | 3 | ||||
-rw-r--r-- | l10n/pt_BR.js | 3 | ||||
-rw-r--r-- | l10n/pt_BR.json | 3 | ||||
-rw-r--r-- | lib/Share/RoomShareProvider.php | 4 | ||||
-rw-r--r-- | src/components/MessagesList/MessagesGroup/Message/Message.spec.js | 14 | ||||
-rw-r--r-- | src/components/MessagesList/MessagesGroup/Message/Message.vue | 19 | ||||
-rw-r--r-- | src/components/MessagesList/MessagesGroup/Message/MessageButtonsBar/MessageButtonsBar.vue | 8 | ||||
-rw-r--r-- | src/components/NewMessageForm/NewMessageForm.vue | 2 | ||||
-rw-r--r-- | src/store/messagesStore.js | 7 | ||||
-rw-r--r-- | src/store/reactionsStore.js | 15 | ||||
-rw-r--r-- | src/views/Dashboard.vue | 3 |
16 files changed, 263 insertions, 69 deletions
diff --git a/.github/workflows/appstore-build-publish.yml b/.github/workflows/appstore-build-publish.yml index ba532ca14..fc04383c6 100644 --- a/.github/workflows/appstore-build-publish.yml +++ b/.github/workflows/appstore-build-publish.yml @@ -23,16 +23,16 @@ jobs: - name: Check actor permission uses: skjnldsv/check-actor-permission@v2 with: - require: admin + require: write - name: Set app env run: | - # Split and keep last + # Split and keep last echo "APP_NAME=${GITHUB_REPOSITORY##*/}" >> $GITHUB_ENV echo "APP_VERSION=${GITHUB_REF##*/}" >> $GITHUB_ENV - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: path: ${{ env.APP_NAME }} @@ -41,22 +41,22 @@ jobs: uses: skjnldsv/xpath-action@master with: filename: ${{ env.APP_NAME }}/appinfo/info.xml - expression: '//info//dependencies//nextcloud/@min-version' + expression: "//info//dependencies//nextcloud/@min-version" - name: Read package.json node and npm engines version - uses: skjnldsv/read-package-engines-version-actions@v1.1 + uses: skjnldsv/read-package-engines-version-actions@v1.2 id: versions # Continue if no package.json continue-on-error: true with: path: ${{ env.APP_NAME }} - fallbackNode: '^12' - fallbackNpm: '^6' + fallbackNode: "^12" + fallbackNpm: "^6" - name: Set up node ${{ steps.versions.outputs.nodeVersion }} # Skip if no package.json if: ${{ steps.versions.outputs.nodeVersion }} - uses: actions/setup-node@v2 + uses: actions/setup-node@v3 with: node-version: ${{ steps.versions.outputs.nodeVersion }} @@ -91,11 +91,29 @@ jobs: npm ci npm run build - - name: Package ${{ env.APP_NAME }} ${{ env.APP_VERSION }} - # Try krankerl, fallback to makefile + - name: Check Krankerl config + id: krankerl + uses: andstor/file-existence-action@v1 + with: + files: ${{ env.APP_NAME }}/krankerl.toml + + - name: Install Krankerl + if: steps.krankerl.outputs.files_exists == 'true' + run: | + wget https://github.com/ChristophWurst/krankerl/releases/download/v0.13.0/krankerl_0.13.0_amd64.deb + sudo dpkg -i krankerl_0.13.0_amd64.deb + + - name: Package ${{ env.APP_NAME }} ${{ env.APP_VERSION }} with krankerl + if: steps.krankerl.outputs.files_exists == 'true' + run: | + cd ${{ env.APP_NAME }} + krankerl package + + - name: Package ${{ env.APP_NAME }} ${{ env.APP_VERSION }} with makefile + if: steps.krankerl.outputs.files_exists != 'true' run: | cd ${{ env.APP_NAME }} - krankerl package || make appstore + make appstore - name: Checkout server ${{ fromJSON(steps.appinfo.outputs.result).nextcloud.min-version }} continue-on-error: true @@ -106,7 +124,7 @@ jobs: unzip latest-$NCVERSION.zip - name: Checkout server master fallback - uses: actions/checkout@v2 + uses: actions/checkout@v3 if: ${{ steps.server-checkout.outcome != 'success' }} with: repository: nextcloud/server diff --git a/CHANGELOG.md b/CHANGELOG.md index afd8a360d..1305be75c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,46 @@ # Changelog All notable changes to this project will be documented in this file. +## 14.0.0-beta.1 – 2022-04-08 +### Added +- Reactions for chat messages +- Implement `OCP\Talk\IBroker` to allow apps to create conversations +- Sharing a browser tab in Chrome-based browsers can now also share the audio of that tab + [#6810](https://github.com/nextcloud/spreed/pull/6810) + +### Still in progress +- Media tab showing all shared items of the conversation + +### Changed +- Messages of shared objects and files can now be deleted (shares will be removed, files persist) + [#7047](https://github.com/nextcloud/spreed/pull/7047) +- Actions like calling and chatting in big rooms should now be much smoother +- Compatibility with Nextcloud 24 + +## 13.0.5 – 2022-04-08 +### Fixed +- Fix reconnection when media permissions change + [#7092](https://github.com/nextcloud/spreed/pull/7092) +- Fix forced reconnection without the High-performance backend + [#7095](https://github.com/nextcloud/spreed/pull/7095) +- Compatibility with LDAP user backends and more than 64 characters display names + [#7073](https://github.com/nextcloud/spreed/pull/7073) +- Compatibility with Oracle and MySQL ONLY_FULL_GROUP_BY + [#7036](https://github.com/nextcloud/spreed/pull/7036) +- Fix broken avatars when search for users to add to a conversation + [#7037](https://github.com/nextcloud/spreed/pull/7037) +- Fix sort order of guests and logged-in users + [#7053](https://github.com/nextcloud/spreed/pull/7053) +- Allow copying links of open conversations without joining + [#7070](https://github.com/nextcloud/spreed/pull/7070) + +## 12.2.5 – 2022-04-08 +### Fixed +- Compatibility with LDAP user backends and more than 64 characters display names + [#7074](https://github.com/nextcloud/spreed/pull/7074) +- Compatibility with Oracle and MySQL ONLY_FULL_GROUP_BY + [#7040](https://github.com/nextcloud/spreed/pull/7040) + ## 13.0.4 – 2022-03-17 ### Fixed - Fix several modals, dialogs and popovers in fullscreen mode @@ -63,6 +63,7 @@ appstore: --exclude=composer.json \ --exclude=composer.lock \ --exclude=docs \ + --exclude=.drone.jsonnet \ --exclude=.drone.yml \ --exclude=.eslintignore \ --exclude=.eslintrc.js \ @@ -77,8 +78,10 @@ appstore: --exclude=node_modules \ --exclude=package.json \ --exclude=package-lock.json \ - --exclude=.php_cs.dist \ + --exclude=.php-cs-fixer.cache \ + --exclude=.php-cs-fixer.dist.php \ --exclude=.php_cs.cache \ + --exclude=.php_cs.dist \ --exclude=psalm.xml \ --exclude=README.md \ --exclude=src \ diff --git a/appinfo/info.xml b/appinfo/info.xml index f9afae1ff..593471a19 100644 --- a/appinfo/info.xml +++ b/appinfo/info.xml @@ -16,7 +16,7 @@ And in the works for the [coming versions](https://github.com/nextcloud/spreed/m ]]></description> - <version>14.0.0-dev.3</version> + <version>14.0.0-beta.1</version> <licence>agpl</licence> <author>Aleksandra Lazarević</author> diff --git a/docs/Talkbuchet.js b/docs/Talkbuchet.js index 513b71c94..c8dd34df3 100644 --- a/docs/Talkbuchet.js +++ b/docs/Talkbuchet.js @@ -22,22 +22,27 @@ /** * HOW TO SETUP: * ----------------------------------------------------------------------------- - * - Set the right values in "user" and "appToken" (a user must be used; guests - * do not work; generate an apptoken at index.php/settings/user/security ). - * - If HPB clustering is enabled, set the token of a conversation in "token" - * (otherwise leave empty). - * - Set whether to use audio, video or both in "mediaConstraints". - * - Set the desired numbers in "publishersCount" and - * "subscribersPerPublisherCount" (in a regular call with N participants you - * would have N publishers and N-1 subscribers). + * - In the browser, log in the Nextcloud server (with the same user as in this + * script). + * - Copy and paste the full script in the console of the browser. + * - Set the user and appToken (a user must be used; guests do not work; + * generate an apptoken at index.php/settings/user/security) by calling + * "setCredentials(user, appToken)" in the console. + * - If HPB clustering is enabled, set the token of a conversation (otherwise + * leave empty) by calling "setToken(token)" in the console. + * - If media other than just audio should be used, start it by calling + * "startMedia(audio, video)" in the console. + * - Set the desired numbers of publishers and subscribers per publisher (in a + * regular call with N participants you would have N publishers and N-1 + * subscribers) by calling "setPublishersAndSubscribersCount(publishersCount, + * subscribersPerPublisherCount)" in the console. * * HOW TO RUN: * ----------------------------------------------------------------------------- - * - In the browser, log in the Nextcloud server (with the same user as in this - * script). - * - Copy and paste the full script in the console of the browser to run it. - * - To run it again execute "closeConnections()" in the console; then you must - * reload the page and copy and paste the script again. + * - Once all the needed parameters are set execute "siege()" in the console. + * - To run it again execute "siege()" again in the console; if any parameter + * needs to be changed it is recommended to first stop the previous siege by + * calling "closeConnections()" in the console before changing the parameters. * * HOW TO ENABLE AND DISABLE THE MEDIA DURING A TEST: * ----------------------------------------------------------------------------- @@ -126,27 +131,24 @@ // a second time causes the first guest to be unregistered. // Regular users do not need to join the conversation, so the same user can be // connected several times to the HPB. -const user = '' -const appToken = '' - -const signalingApiVersion = 2 // FIXME get from capabilities endpoint -const conversationApiVersion = 3 // FIXME get from capabilities endpoint +let user = '' +let appToken = '' // The conversation token is only strictly needed for guests or if HPB // clustering is enabled. -const token = '' +let token = '' // Number of streams to send -const publishersCount = 5 +let publishersCount = 5 // Number of streams to receive -const subscribersPerPublisherCount = 40 +let subscribersPerPublisherCount = 40 const mediaConstraints = { audio: true, video: false, } -const connectionWarningTimeout = 5000 +let connectionWarningTimeout = 5000 /* * End of configuration section @@ -155,15 +157,55 @@ const connectionWarningTimeout = 5000 // To run the script the current page in the browser must be a page of the // target Nextcloud instance, as cross-doman requests are not allowed, so the // host is directly got from the current location. -const talkOcsApiUrl = 'https://' + window.location.host + '/ocs/v2.php/apps/spreed/api/' +const host = 'https://' + window.location.host + +const capabitiliesUrl = host + '/ocs/v1.php/cloud/capabilities' + +async function getCapabilities() { + const fetchOptions = { + headers: { + 'OCS-ApiRequest': true, + 'Accept': 'json', + }, + } + + const capabilitiesResponse = await fetch(capabitiliesUrl, fetchOptions) + const capabilities = await capabilitiesResponse.json() + + return capabilities.ocs.data +} + +const capabilities = await getCapabilities() + +function extractFeatureVersion(feature) { + const talkFeatures = capabilities?.capabilities?.spreed?.features + if (!talkFeatures) { + console.error('Talk features not found', capabilities) + throw new Error() + } + + for (const talkFeature of talkFeatures) { + if (talkFeature.startsWith(feature + '-v')) { + return talkFeature.substring(feature.length + 2) + } + } + + console.error('Failed to get feature version for ' + feature, talkFeatures) + throw new Error() +} + +const signalingApiVersion = extractFeatureVersion('signaling') +const conversationApiVersion = extractFeatureVersion('conversation') + +const talkOcsApiUrl = host + '/ocs/v2.php/apps/spreed/api/' const signalingSettingsUrl = talkOcsApiUrl + 'v' + signalingApiVersion + '/signaling/settings' const signalingBackendUrl = talkOcsApiUrl + 'v' + signalingApiVersion + '/signaling/backend' -const joinRoomUrl = talkOcsApiUrl + 'v' + conversationApiVersion + '/room/' + token + '/participants/active' +let joinRoomUrl = talkOcsApiUrl + 'v' + conversationApiVersion + '/room/' + token + '/participants/active' const publishers = [] const subscribers = [] -const stream = await navigator.mediaDevices.getUserMedia(mediaConstraints) +let stream async function getSignalingSettings(user, appToken, token) { const fetchOptions = { @@ -608,14 +650,21 @@ const closeConnections = function() { subscribers.forEach(subscriber => { subscriber.peerConnection.close() }) + subscribers.splice(0) Object.values(publishers).forEach(publisher => { publisher.peerConnection.close() }) - - stream.getTracks().forEach(track => { - track.stop() + Object.keys(publishers).forEach(publisherSessionId => { + delete publishers[publisherSessionId] }) + + if (stream) { + stream.getTracks().forEach(track => { + track.stop() + }) + stream = null + } } const setAudioEnabled = function(enabled) { @@ -723,7 +772,58 @@ const checkSubscribersConnections = function() { console.info(' - Failed: ' + (iceConnectionStateCount['failed'] ?? 0)) } -console.info('Preparing to siege') +const setCredentials = function(userToSet, appTokenToSet) { + user = userToSet + appToken = appTokenToSet +} + +const setToken = function(tokenToSet) { + token = tokenToSet + + joinRoomUrl = talkOcsApiUrl + 'v' + conversationApiVersion + '/room/' + token + '/participants/active' +} + +const setPublishersAndSubscribersCount = function(publishersCountToSet, subscribersPerPublisherCountToSet) { + publishersCount = publishersCountToSet + subscribersPerPublisherCount = subscribersPerPublisherCountToSet +} + +const startMedia = async function(audio, video) { + if (stream) { + stream.getTracks().forEach(track => { + track.stop() + }) + } + + if (audio !== undefined) { + mediaConstraints.audio = audio + } + if (video !== undefined) { + mediaConstraints.video = video + } + + stream = await navigator.mediaDevices.getUserMedia(mediaConstraints) +} + +const setConnectionWarningTimeout = function(connectionWarningTimeoutToSet) { + connectionWarningTimeout = connectionWarningTimeoutToSet +} + +const siege = async function() { + if (!user || !appToken) { + console.error('Credentials (user and appToken) are not set') + + return + } -await initPublishers() -await initSubscribers() + closeConnections() + + if (!stream) { + await startMedia() + } + + console.info('Preparing to siege') + + await initPublishers() + await initSubscribers() +} diff --git a/docs/reaction.md b/docs/reaction.md index f4ed4b7b4..e135ef482 100644 --- a/docs/reaction.md +++ b/docs/reaction.md @@ -16,10 +16,9 @@ Base endpoint is: `/ocs/v2.php/apps/spreed/api/v1` * Response: - Status code: + `200 OK` Reaction already exists - + `201 Created` + + `201 Created` User reacted with a new reaction + `400 Bad Request` In case of no reaction support, message out of reactions context or any other error + `404 Not Found` When the conversation or message to react could not be found for the participant - + `409 Conflict` User already did this reaction to this message - Data: Array with data of reactions: diff --git a/l10n/pt_BR.js b/l10n/pt_BR.js index 248b7d704..1eae61749 100644 --- a/l10n/pt_BR.js +++ b/l10n/pt_BR.js @@ -47,6 +47,7 @@ OC.L10N.register( "The command does not exist" : "O comando não existe", "An error occurred while running the command. Please ask an administrator to check the logs." : "Ocorreu um erro ao executar o comando. Por favor, peça a um administrador para verificar os logs.", "Talk updates ✅" : "Atualizações do Talk ✅", + "Reaction deleted by author" : "Reação excluída pelo autor", "{actor} created the conversation" : "{actor} criou a conversa", "You created the conversation" : "Você criou uma conversa", "An administrator created the conversation" : "Um administrador criou a conversa", @@ -148,6 +149,8 @@ OC.L10N.register( "You stopped Matterbridge" : "Você parou Matterbridge.", "{actor} deleted a message" : "{actor} excluiu uma mensagem", "You deleted a message" : "Você excluiu uma mensagem", + "{actor} deleted a reaction" : "{actor} excluiu uma reação", + "You deleted a reaction" : "Você excluiu uma reação", "{actor} cleared the history of the conversation" : "{actor} limpou o histórico da conversa ", "You cleared the history of the conversation" : "Você limpou o histórico da conversa ", "Message deleted by author" : "Mensagem excluída pelo autor", diff --git a/l10n/pt_BR.json b/l10n/pt_BR.json index eda94ab66..d8062ec06 100644 --- a/l10n/pt_BR.json +++ b/l10n/pt_BR.json @@ -45,6 +45,7 @@ "The command does not exist" : "O comando não existe", "An error occurred while running the command. Please ask an administrator to check the logs." : "Ocorreu um erro ao executar o comando. Por favor, peça a um administrador para verificar os logs.", "Talk updates ✅" : "Atualizações do Talk ✅", + "Reaction deleted by author" : "Reação excluída pelo autor", "{actor} created the conversation" : "{actor} criou a conversa", "You created the conversation" : "Você criou uma conversa", "An administrator created the conversation" : "Um administrador criou a conversa", @@ -146,6 +147,8 @@ "You stopped Matterbridge" : "Você parou Matterbridge.", "{actor} deleted a message" : "{actor} excluiu uma mensagem", "You deleted a message" : "Você excluiu uma mensagem", + "{actor} deleted a reaction" : "{actor} excluiu uma reação", + "You deleted a reaction" : "Você excluiu uma reação", "{actor} cleared the history of the conversation" : "{actor} limpou o histórico da conversa ", "You cleared the history of the conversation" : "Você limpou o histórico da conversa ", "Message deleted by author" : "Mensagem excluída pelo autor", diff --git a/lib/Share/RoomShareProvider.php b/lib/Share/RoomShareProvider.php index df8311f10..287477884 100644 --- a/lib/Share/RoomShareProvider.php +++ b/lib/Share/RoomShareProvider.php @@ -970,12 +970,12 @@ class RoomShareProvider implements IShareProvider { $userList = $this->participantService->getParticipantUserIds($room); foreach ($userList as $uid) { - $users[$uid] = $users[$uid] ?? []; + $users[$uid] ??= []; $users[$uid][$row['id']] = $row; } } elseif ($type === self::SHARE_TYPE_USERROOM && $currentAccess === true) { $uid = $row['share_with']; - $users[$uid] = $users[$uid] ?? []; + $users[$uid] ??= []; $users[$uid][$row['id']] = $row; } } diff --git a/src/components/MessagesList/MessagesGroup/Message/Message.spec.js b/src/components/MessagesList/MessagesGroup/Message/Message.spec.js index a12c40f26..0bf661642 100644 --- a/src/components/MessagesList/MessagesGroup/Message/Message.spec.js +++ b/src/components/MessagesList/MessagesGroup/Message/Message.spec.js @@ -809,8 +809,10 @@ describe('Message.vue', () => { test('dispatches store action upon picking an emoji from the emojipicker', () => { const addReactionToMessageAction = jest.fn() const userHasReactedGetter = jest.fn().mockReturnValue(() => false) + const reactionsLoadedGetter = jest.fn().mockReturnValue(() => true) testStoreConfig.modules.quoteReplyStore.actions.addReactionToMessage = addReactionToMessageAction testStoreConfig.modules.messagesStore.getters.userHasReacted = userHasReactedGetter + testStoreConfig.modules.messagesStore.getters.reactionsLoaded = reactionsLoadedGetter store = new Store(testStoreConfig) @@ -821,11 +823,6 @@ describe('Message.vue', () => { stubs: { EmojiPicker, }, - data() { - return { - detailedReactionsRequested: true, - } - }, }) const emojiPicker = wrapper.findComponent(EmojiPicker) @@ -844,8 +841,10 @@ describe('Message.vue', () => { test('dispatches store action to remove an emoji upon clicking reaction button', async () => { const removeReactionFromMessageAction = jest.fn() const userHasReactedGetter = jest.fn().mockReturnValue(() => true) + const reactionsLoadedGetter = jest.fn().mockReturnValue(() => true) testStoreConfig.modules.quoteReplyStore.actions.removeReactionFromMessage = removeReactionFromMessageAction testStoreConfig.modules.messagesStore.getters.userHasReacted = userHasReactedGetter + testStoreConfig.modules.messagesStore.getters.reactionsLoaded = reactionsLoadedGetter store = new Store(testStoreConfig) @@ -853,11 +852,6 @@ describe('Message.vue', () => { localVue, store, propsData: messageProps, - data() { - return { - detailedReactionsRequested: true, - } - }, }) // Click reaction button upon having already reacted diff --git a/src/components/MessagesList/MessagesGroup/Message/Message.vue b/src/components/MessagesList/MessagesGroup/Message/Message.vue index 2e9d073f9..28181b355 100644 --- a/src/components/MessagesList/MessagesGroup/Message/Message.vue +++ b/src/components/MessagesList/MessagesGroup/Message/Message.vue @@ -359,7 +359,7 @@ export default { isActionMenuOpen: false, isEmojiPickerOpen: false, isReactionsMenuOpen: false, - detailedReactionsRequested: false, + detailedReactionsLoading: false, } }, @@ -568,6 +568,10 @@ export default { detailedReactions() { return this.$store.getters.reactions(this.token, this.id) }, + + detailedReactionsLoaded() { + return this.$store.getters.reactionsLoaded(this.token, this.id) + }, }, watch: { @@ -625,7 +629,7 @@ export default { }, handleReactionsMouseOver() { - if (this.hasReactions && !this.detailedReactionsRequested) { + if (this.hasReactions && !this.detailedReactionsLoaded) { this.getReactions() } }, @@ -637,24 +641,29 @@ export default { }, async getReactions() { + if (this.detailedReactionsLoading) { + // FIXME not sure how to await the other execution + } + try { /** * Get reaction details when the message is hovered for the first * time. After that we rely on system messages to update the * reactions. */ - this.detailedReactionsRequested = true + this.detailedReactionsLoading = true await this.$store.dispatch('getReactions', { token: this.token, messageId: this.id, }) + this.detailedReactionsLoading = false } catch { - this.detailedReactionsRequested = false + this.detailedReactionsLoading = false } }, async handleReactionClick(clickedEmoji) { - if (!this.detailedReactionsRequested) { + if (!this.detailedReactionsLoaded) { await this.getReactions() } // Check if current user has already added this reaction to the message diff --git a/src/components/MessagesList/MessagesGroup/Message/MessageButtonsBar/MessageButtonsBar.vue b/src/components/MessagesList/MessagesGroup/Message/MessageButtonsBar/MessageButtonsBar.vue index f02664994..b6e2a5f8a 100644 --- a/src/components/MessagesList/MessagesGroup/Message/MessageButtonsBar/MessageButtonsBar.vue +++ b/src/components/MessagesList/MessagesGroup/Message/MessageButtonsBar/MessageButtonsBar.vue @@ -67,7 +67,7 @@ :href="linkToFile"> {{ t('spreed', 'Go to file') }} </ActionLink> - <ActionButton v-if="!isCurrentGuest && !isFileShare" + <ActionButton v-if="!isCurrentGuest && !isFileShare && !isDeletedMessage" :close-after-click="true" @click.stop="showForwarder = true"> <Share slot="icon" @@ -326,7 +326,7 @@ export default { }, acceptsReactions() { - return !this.isConversationReadOnly + return !this.isConversationReadOnly && !this.isDeletedMessage }, messageActions() { @@ -356,6 +356,10 @@ export default { isConversationReadOnly() { return this.conversation.readOnly === CONVERSATION.STATE.READ_ONLY }, + + isDeletedMessage() { + return this.messageType === 'comment_deleted' + }, }, methods: { diff --git a/src/components/NewMessageForm/NewMessageForm.vue b/src/components/NewMessageForm/NewMessageForm.vue index 4ffb5a2b1..0942e316e 100644 --- a/src/components/NewMessageForm/NewMessageForm.vue +++ b/src/components/NewMessageForm/NewMessageForm.vue @@ -68,7 +68,7 @@ @select="addEmoji"> <Button :disabled="disabled" :aria-label="t('spreed', 'Add emoji')" - type="tertiary" + type="tertiary-no-background" :aria-haspopup="true"> <EmoticonOutline :size="16" decorative diff --git a/src/store/messagesStore.js b/src/store/messagesStore.js index 46346b428..e10fd2094 100644 --- a/src/store/messagesStore.js +++ b/src/store/messagesStore.js @@ -391,6 +391,13 @@ const actions = { }) } + if (message.systemMessage === 'reaction' || message.systemMessage === 'reaction_revoked') { + context.commit('resetReactions', { + token: message.token, + messageId: message.parent, + }) + } + context.commit('addMessage', message) }, diff --git a/src/store/reactionsStore.js b/src/store/reactionsStore.js index c9f1c67fc..c70a14a0b 100644 --- a/src/store/reactionsStore.js +++ b/src/store/reactionsStore.js @@ -41,6 +41,14 @@ const getters = { } }, + reactionsLoaded: (state) => (token, messageId) => { + if (state.reactions?.[token]?.[messageId]) { + return true + } else { + return false + } + }, + // Checks if a user has already reacted to a message with a particular reaction userHasReacted: (state) => (actorType, actorId, token, messageId, reaction) => { if (!state?.reactions?.[token]?.[messageId]?.[reaction]) { @@ -60,6 +68,13 @@ const mutations = { } Vue.set(state.reactions[token], messageId, reactions) }, + + resetReactions(state, { token, messageId }) { + if (!state.reactions[token]) { + Vue.set(state.reactions, token, {}) + } + Vue.delete(state.reactions[token], messageId) + }, } const actions = { diff --git a/src/views/Dashboard.vue b/src/views/Dashboard.vue index eed707118..66834ef0f 100644 --- a/src/views/Dashboard.vue +++ b/src/views/Dashboard.vue @@ -31,8 +31,7 @@ <DashboardWidgetItem :target-url="getItemTargetUrl(item)" :main-text="getMainText(item)" :sub-text="getSubText(item)" - :item="item" - v-on="handlers"> + :item="item"> <template #avatar> <ConversationIcon :item="item" :hide-favorite="true" |