summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMaksim Sukharev <antreesy.web@gmail.com>2024-01-15 11:07:50 +0100
committerMaksim Sukharev <antreesy.web@gmail.com>2024-01-18 11:21:48 +0100
commit20b3e34950b00d2981362df459820918b8d1bf52 (patch)
treeb37434c0a2c9fe44360fd640395eebbcb9503bc2
parent086728d6c0156ec41ac26506304ec0f3d59f8b10 (diff)
enh(message): pass destructured message object as $props to children
Signed-off-by: Maksim Sukharev <antreesy.web@gmail.com>
-rw-r--r--src/components/MessagesList/MessagesGroup/Message/Message.vue76
-rw-r--r--src/components/MessagesList/MessagesGroup/Message/MessageButtonsBar/MessageButtonsBar.spec.js20
-rw-r--r--src/components/MessagesList/MessagesGroup/Message/MessageButtonsBar/MessageButtonsBar.vue67
-rw-r--r--src/components/MessagesList/MessagesGroup/Message/MessageButtonsBar/MessageForwarder.vue15
-rw-r--r--src/components/MessagesList/MessagesGroup/Message/MessagePart/MessageBody.vue2
-rw-r--r--src/components/MessagesList/MessagesGroup/MessagesGroup.vue64
-rw-r--r--src/components/MessagesList/MessagesList.spec.js39
-rw-r--r--src/components/MessagesList/MessagesList.vue1
8 files changed, 111 insertions, 173 deletions
diff --git a/src/components/MessagesList/MessagesGroup/Message/Message.vue b/src/components/MessagesList/MessagesGroup/Message/Message.vue
index b6ab4f9fb..dd6075371 100644
--- a/src/components/MessagesList/MessagesGroup/Message/Message.vue
+++ b/src/components/MessagesList/MessagesGroup/Message/Message.vue
@@ -36,24 +36,10 @@
'system' : isSystemMessage,
'combined-system': isCombinedSystemMessage}"
class="message-body">
- <MessageBody :id="id"
- :token="token"
- :parent="parent"
- :markdown="markdown"
- :message="message"
- :message-type="messageType"
- :system-message="systemMessage"
- :message-parameters="messageParameters"
+ <MessageBody v-bind="{...$props, ...readInfoProps}"
:rich-parameters="richParameters"
- :timestamp="timestamp"
:is-deleting="isDeleting"
- :is-temporary="isTemporary"
- :has-call="conversation.hasCall"
- :sending-failure="sendingFailure"
- :show-common-read-icon="showCommonReadIcon"
- :common-read-icon-tooltip="commonReadIconTooltip"
- :show-sent-icon="showSentIcon"
- :sent-icon-tooltip="sentIconTooltip" />
+ :has-call="conversation.hasCall" />
<!-- reactions buttons and popover with details -->
<Reactions v-if="Object.keys(reactions).length"
@@ -68,20 +54,13 @@
<MessageButtonsBar v-if="showMessageButtonsBar"
ref="messageButtonsBar"
class="message-buttons-bar"
+ v-bind="{...$props, ...readInfoProps}"
:is-translation-available="isTranslationAvailable"
:is-action-menu-open.sync="isActionMenuOpen"
:is-emoji-picker-open.sync="isEmojiPickerOpen"
:is-reactions-menu-open.sync="isReactionsMenuOpen"
:is-forwarder-open.sync="isForwarderOpen"
- :message-api-data="messageApiData"
- :message-object="messageObject"
:can-react="canReact"
- v-bind="$props"
- :previous-message-id="previousMessageId"
- :show-common-read-icon="showCommonReadIcon"
- :common-read-icon-tooltip="commonReadIconTooltip"
- :show-sent-icon="showSentIcon"
- :sent-icon-tooltip="sentIconTooltip"
@show-translate-dialog="isTranslateDialogOpen = true"
@reply="handleReply"
@edit="handleEdit"
@@ -100,6 +79,11 @@
</div>
</div>
+ <MessageForwarder v-if="isForwarderOpen"
+ :id="id"
+ :token="token"
+ @close="isForwarderOpen = false" />
+
<MessageTranslateDialog v-if="isTranslationAvailable && isTranslateDialogOpen"
:message="message"
:rich-parameters="richParameters"
@@ -123,6 +107,7 @@ import { showError, showSuccess, showWarning, TOAST_DEFAULT_TIMEOUT } from '@nex
import NcButton from '@nextcloud/vue/dist/Components/NcButton.js'
import MessageButtonsBar from './MessageButtonsBar/MessageButtonsBar.vue'
+import MessageForwarder from './MessageButtonsBar/MessageForwarder.vue'
import MessageTranslateDialog from './MessageButtonsBar/MessageTranslateDialog.vue'
import Contact from './MessagePart/Contact.vue'
import DeckCard from './MessagePart/DeckCard.vue'
@@ -148,8 +133,9 @@ export default {
components: {
MessageBody,
- MessageTranslateDialog,
MessageButtonsBar,
+ MessageForwarder,
+ MessageTranslateDialog,
NcButton,
Reactions,
// Icons
@@ -301,16 +287,6 @@ export default {
default: '',
},
- lastEditActorId: {
- type: String,
- default: '',
- },
-
- lastEditActorType: {
- type: String,
- default: '',
- },
-
lastEditTimestamp: {
type: Number,
default: 0,
@@ -356,10 +332,6 @@ export default {
return !this.isLastMessage && this.id === this.$store.getters.getVisualLastReadMessageId(this.token)
},
- messageObject() {
- return this.$store.getters.message(this.token, this.id)
- },
-
isSystemMessage() {
return this.systemMessage !== ''
},
@@ -391,7 +363,10 @@ export default {
Object.keys(this.messageParameters).forEach(function(p) {
const type = this.messageParameters[p].type
const mimetype = this.messageParameters[p].mimetype
- const itemType = getItemTypeFromMessage(this.messageObject)
+ const itemType = getItemTypeFromMessage({
+ messageParameters: this.messageParameters,
+ messageType: this.messageType
+ })
if (type === 'user' || type === 'call' || type === 'guest' || type === 'user-group' || type === 'group') {
richParameters[p] = {
component: Mention,
@@ -450,27 +425,20 @@ export default {
&& this.isCombinedSystemMessage && (this.isHovered || !this.isCombinedSystemMessageCollapsed)
},
- sentIconTooltip() {
- return t('spreed', 'Message sent')
- },
-
- commonReadIconTooltip() {
- return t('spreed', 'Message read by everyone who shares their reading status')
- },
-
- messageApiData() {
+ readInfoProps() {
return {
- message: this.messageObject,
- metadata: this.conversation,
- apiVersion: 'v3',
+ showCommonReadIcon: this.showCommonReadIcon,
+ commonReadIconTooltip: t('spreed', 'Message read by everyone who shares their reading status'),
+ showSentIcon: this.showSentIcon,
+ sentIconTooltip: t('spreed', 'Message sent'),
}
},
canReact() {
return this.conversation.readOnly !== CONVERSATION.STATE.READ_ONLY
&& (this.conversation.permissions & PARTICIPANT.PERMISSIONS.CHAT) !== 0
- && this.messageObject.messageType !== 'command'
- && this.messageObject.messageType !== 'comment_deleted'
+ && this.messageType !== 'command'
+ && this.messageType !== 'comment_deleted'
},
isFileShareOnly() {
diff --git a/src/components/MessagesList/MessagesGroup/Message/MessageButtonsBar/MessageButtonsBar.spec.js b/src/components/MessagesList/MessagesGroup/Message/MessageButtonsBar/MessageButtonsBar.spec.js
index 8c2e23259..97e888bca 100644
--- a/src/components/MessagesList/MessagesGroup/Message/MessageButtonsBar/MessageButtonsBar.spec.js
+++ b/src/components/MessagesList/MessagesGroup/Message/MessageButtonsBar/MessageButtonsBar.spec.js
@@ -60,6 +60,8 @@ describe('MessageButtonsBar.vue', () => {
isTranslationAvailable: false,
canReact: true,
isReactionsMenuOpen: false,
+ isActionMenuOpen: false,
+ isEmojiPickerOpen: false,
isLastRead: false,
isForwarderOpen: false,
timestamp: new Date('2020-05-07 09:23:00').getTime() / 1000,
@@ -67,10 +69,6 @@ describe('MessageButtonsBar.vue', () => {
systemMessage: '',
messageType: 'comment',
previousMessageId: 100,
- messageObject: {},
- messageApiData: {
- apiDummyData: 1,
- },
participant: {
actorId: 'user-id-1',
actorType: ATTENDEE.ACTOR_TYPE.USERS,
@@ -333,7 +331,7 @@ describe('MessageButtonsBar.vue', () => {
test('marks message as unread', async () => {
const updateLastReadMessageAction = jest.fn().mockResolvedValueOnce()
const fetchConversationAction = jest.fn().mockResolvedValueOnce()
- testStoreConfig.modules.conversationsStore.actions.updateLastReadMessage = updateLastReadMessageAction
+ testStoreConfig.modules.messagesStore.actions.updateLastReadMessage = updateLastReadMessageAction
testStoreConfig.modules.conversationsStore.actions.fetchConversation = fetchConversationAction
store = new Store(testStoreConfig)
@@ -437,19 +435,23 @@ describe('MessageButtonsBar.vue', () => {
})
const actionButton = findNcActionButton(wrapper, 'first action')
- expect(actionButton.exists()).toBe(true)
+ expect(actionButton.exists()).toBeTruthy()
await actionButton.find('button').trigger('click')
expect(handler).toHaveBeenCalledWith({
- apiDummyData: 1,
+ apiVersion: 'v3',
+ message: messageProps,
+ metadata: conversationProps,
},)
const actionButton2 = findNcActionButton(wrapper, 'second action')
- expect(actionButton2.exists()).toBe(true)
+ expect(actionButton2.exists()).toBeTruthy()
await actionButton2.find('button').trigger('click')
expect(handler2).toHaveBeenCalledWith({
- apiDummyData: 1,
+ apiVersion: 'v3',
+ message: messageProps,
+ metadata: conversationProps,
})
})
})
diff --git a/src/components/MessagesList/MessagesGroup/Message/MessageButtonsBar/MessageButtonsBar.vue b/src/components/MessagesList/MessagesGroup/Message/MessageButtonsBar/MessageButtonsBar.vue
index 699756087..5a0a75147 100644
--- a/src/components/MessagesList/MessagesGroup/Message/MessageButtonsBar/MessageButtonsBar.vue
+++ b/src/components/MessagesList/MessagesGroup/Message/MessageButtonsBar/MessageButtonsBar.vue
@@ -3,7 +3,7 @@
-
- @author Marco Ambrosini <marcoambrosini@icloud.com>
-
- - @license GNU AGPL version 3 or any later version
+ - @license AGPL-3.0-or-later
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as
@@ -66,12 +66,12 @@
{{ messageDateTime }}
</NcActionText>
<!-- Edited message timestamp -->
- <NcActionButtonGroup v-if="messageObject.lastEditTimestamp">
+ <NcActionButtonGroup v-if="lastEditTimestamp">
<NcActionText>
<template #icon>
<ClockEditOutline :size="16" />
</template>
- {{ messageObject.lastEditActorDisplayName }}
+ {{ lastEditActorDisplayName }}
</NcActionText>
<NcActionText>
{{ editedDateTime }}
@@ -263,9 +263,6 @@
</NcButton>
</NcEmojiPicker>
</template>
- <MessageForwarder v-if="isForwarderOpen"
- :message-object="messageObject"
- @close="closeForwarder" />
</div>
</template>
@@ -309,8 +306,6 @@ import NcActionText from '@nextcloud/vue/dist/Components/NcActionText.js'
import NcButton from '@nextcloud/vue/dist/Components/NcButton.js'
import NcEmojiPicker from '@nextcloud/vue/dist/Components/NcEmojiPicker.js'
-import MessageForwarder from './MessageForwarder.vue'
-
import { PARTICIPANT, CONVERSATION, ATTENDEE } from '../../../../../constants.js'
import { getMessageReminder, removeMessageReminder, setMessageReminder } from '../../../../../services/remindersService.js'
import { copyConversationLinkToClipboard } from '../../../../../services/urlService.js'
@@ -324,7 +319,6 @@ export default {
name: 'MessageButtonsBar',
components: {
- MessageForwarder,
NcActionButtonGroup,
NcActionButton,
NcActionInput,
@@ -360,6 +354,8 @@ export default {
inject: ['getMessagesListScroller'],
+ inheritAttrs: false,
+
props: {
token: {
type: String,
@@ -376,11 +372,6 @@ export default {
required: true,
},
- messageObject: {
- type: Object,
- required: true,
- },
-
actorId: {
type: String,
required: true,
@@ -431,16 +422,27 @@ export default {
required: true,
},
- messageApiData: {
- type: Object,
- required: true,
+ lastEditActorDisplayName: {
+ type: String,
+ default: '',
+ },
+ lastEditTimestamp: {
+ type: Number,
+ default: 0,
},
+ isActionMenuOpen: {
+ type: Boolean,
+ required: true,
+ },
+ isEmojiPickerOpen: {
+ type: Boolean,
+ required: true,
+ },
isReactionsMenuOpen: {
type: Boolean,
required: true,
},
-
isForwarderOpen: {
type: Boolean,
required: true,
@@ -607,7 +609,7 @@ export default {
},
editedDateTime() {
- return moment(this.messageObject.lastEditTimestamp * 1000).format('lll')
+ return moment(this.lastEditTimestamp * 1000).format('lll')
},
reminderOptions() {
@@ -660,8 +662,19 @@ export default {
},
clearReminderLabel() {
+ if (!this.currentReminder) {
+ return ''
+ }
return t('spreed', 'Clear reminder – {timeLocale}', { timeLocale: moment(this.currentReminder.timestamp * 1000).format('ddd LT') })
},
+
+ messageApiData() {
+ return {
+ message: this.$store.getters.message(this.token, this.id),
+ metadata: this.$store.getters.conversation(this.token),
+ apiVersion: 'v3',
+ }
+ },
},
watch: {
@@ -684,9 +697,9 @@ export default {
},
async handleCopyMessageText() {
- let parsedText = this.messageObject.message
+ let parsedText = this.message
- for (const [key, value] of Object.entries(this.messageObject.messageParameters)) {
+ for (const [key, value] of Object.entries(this.messageParameters)) {
if (value?.type === 'call') {
parsedText = parsedText.replace(new RegExp(`{${key}}`, 'g'), '@all')
} else if (value?.type === 'user') {
@@ -720,10 +733,10 @@ export default {
handleReactionClick(selectedEmoji) {
// Add reaction only if user hasn't reacted yet
- if (!this.messageObject.reactionsSelf?.includes(selectedEmoji)) {
+ if (!this.reactionsSelf?.includes(selectedEmoji)) {
this.reactionsStore.addReactionToMessage({
token: this.token,
- messageId: this.messageObject.id,
+ messageId: this.id,
selectedEmoji,
})
} else {
@@ -765,7 +778,9 @@ export default {
async forwardToNote() {
try {
- await this.$store.dispatch('forwardMessage', { messageToBeForwarded: this.messageObject })
+ await this.$store.dispatch('forwardMessage', {
+ messageToBeForwarded: this.$store.getters.message(this.token, this.id)
+ })
showSuccess(t('spreed', 'Message forwarded to "Note to self"'))
} catch (error) {
console.error('Error while forwarding message to "Note to self"', error)
@@ -777,10 +792,6 @@ export default {
this.$emit('update:isForwarderOpen', true)
},
- closeForwarder() {
- this.$emit('update:isForwarderOpen', false)
- },
-
// Making sure that the click is outside the MessageButtonsBar
handleClickOutside(event) {
if (event.composedPath().includes(this.$el)) {
diff --git a/src/components/MessagesList/MessagesGroup/Message/MessageButtonsBar/MessageForwarder.vue b/src/components/MessagesList/MessagesGroup/Message/MessageButtonsBar/MessageForwarder.vue
index d7e625c58..09ebdbd28 100644
--- a/src/components/MessagesList/MessagesGroup/Message/MessageButtonsBar/MessageForwarder.vue
+++ b/src/components/MessagesList/MessagesGroup/Message/MessageButtonsBar/MessageForwarder.vue
@@ -3,7 +3,7 @@
-
- @author Marco Ambrosini <marcoambrosini@icloud.com>
-
- - @license GNU AGPL version 3 or any later version
+ - @license AGPL-3.0-or-later
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as
@@ -78,11 +78,12 @@ export default {
},
props: {
- /**
- * The message to be forwarded
- */
- messageObject: {
- type: Object,
+ token: {
+ type: String,
+ required: true,
+ },
+ id: {
+ type: [String, Number],
required: true,
},
},
@@ -122,7 +123,7 @@ export default {
try {
const response = await this.$store.dispatch('forwardMessage', {
targetToken: this.selectedConversationToken,
- messageToBeForwarded: this.messageObject,
+ messageToBeForwarded: this.$store.getters.message(this.token, this.id),
})
this.forwardedMessageID = response.data.ocs.data.id
this.showForwardedConfirmation = true
diff --git a/src/components/MessagesList/MessagesGroup/Message/MessagePart/MessageBody.vue b/src/components/MessagesList/MessagesGroup/Message/MessagePart/MessageBody.vue
index 57dcd5c62..fbdc9e91a 100644
--- a/src/components/MessagesList/MessagesGroup/Message/MessagePart/MessageBody.vue
+++ b/src/components/MessagesList/MessagesGroup/Message/MessagePart/MessageBody.vue
@@ -166,6 +166,8 @@ export default {
ReloadIcon,
},
+ inheritAttrs: false,
+
props: {
id: {
type: [String, Number],
diff --git a/src/components/MessagesList/MessagesGroup/MessagesGroup.vue b/src/components/MessagesList/MessagesGroup/MessagesGroup.vue
index e1f683560..1a37bcd85 100644
--- a/src/components/MessagesList/MessagesGroup/MessagesGroup.vue
+++ b/src/components/MessagesList/MessagesGroup/MessagesGroup.vue
@@ -32,7 +32,7 @@
<ul class="messages">
<li class="messages__author" aria-level="4">
{{ actorDisplayName }}
- <div v-if="lastEditActorDisplayName">
+ <div v-if="lastEditTimestamp">
{{ getLastEditor }}
</div>
</li>
@@ -64,6 +64,7 @@ export default {
AvatarWrapper,
Message,
},
+
inheritAttrs: false,
props: {
@@ -91,55 +92,30 @@ export default {
type: [String, Number],
default: 0,
},
-
- lastEditTimestamp: {
- type: Number,
- default: 0,
- },
- lastEditActorId: {
- type: String,
- default: '',
- },
- lastEditActorType: {
- type: String,
- default: '',
- },
-
- lastEditActorDisplayName: {
- type: String,
- default: ''
- },
},
setup() {
- const guestNameStore = useGuestNameStore()
- return { AVATAR, guestNameStore }
+ return {
+ AVATAR,
+ guestNameStore: useGuestNameStore()
+ }
},
expose: ['highlightMessage'],
computed: {
- /**
- * The message actor type.
- *
- * @return {string}
- */
+ actorId() {
+ return this.messages[0].actorId
+ },
+
actorType() {
return this.messages[0].actorType
},
- /**
- * The message actor id.
- *
- * @return {string}
- */
- actorId() {
- return this.messages[0].actorId
+
+ lastEditTimestamp() {
+ return this.messages[0].lastEditTimestamp
},
- /**
- * The message actor display name.
- *
- * @return {string}
- */
+
actorDisplayName() {
const displayName = this.messages[0].actorDisplayName.trim()
@@ -155,16 +131,18 @@ export default {
},
getLastEditor() {
- if (this.lastEditActorId === this.actorId && this.lastEditActorType === this.actorType) {
+ if (!this.lastEditTimestamp) {
+ return ''
+ } else if (this.messages[0].lastEditActorId === this.actorId
+ && this.messages[0].lastEditActorType === this.actorType) {
// TRANSLATORS Edited by the author of the message themselves
return t('spreed', '(edited)')
- } else if (this.lastEditActorId === this.$store.getters.getActorId()
- && this.lastEditActorType === this.$store.getters.getActorType()) {
+ } else if (this.messages[0].lastEditActorId === this.$store.getters.getActorId()
+ && this.messages[0].lastEditActorType === this.$store.getters.getActorType()) {
return t('spreed', '(edited by you)')
} else {
- return t('spreed', '(edited by {moderator})', { moderator: this.lastEditActorDisplayName })
+ return t('spreed', '(edited by {moderator})', { moderator: this.messages[0].lastEditActorDisplayName })
}
-
},
disableMenu() {
diff --git a/src/components/MessagesList/MessagesList.spec.js b/src/components/MessagesList/MessagesList.spec.js
index fe0f64024..ac5211064 100644
--- a/src/components/MessagesList/MessagesList.spec.js
+++ b/src/components/MessagesList/MessagesList.spec.js
@@ -129,23 +129,16 @@ describe('MessagesList.vue', () => {
expect(group.props('messages')).toStrictEqual(messagesGroup1)
expect(group.props('previousMessageId')).toBe(0)
expect(group.props('nextMessageId')).toBe(200)
- // using attributes to access v-bind props
- expect(group.attributes('actorid')).toBe('alice')
- expect(group.attributes('actortype')).toBe(ATTENDEE.ACTOR_TYPE.USERS)
group = groups.at(1)
expect(group.props('messages')).toStrictEqual(messagesGroup2)
expect(group.props('previousMessageId')).toBe(110)
expect(group.props('nextMessageId')).toBe(300)
- expect(group.attributes('actorid')).toBe('bob')
- expect(group.attributes('actortype')).toBe(ATTENDEE.ACTOR_TYPE.USERS)
group = groups.at(2)
expect(group.props('messages')).toStrictEqual(messagesGroup3)
expect(group.props('previousMessageId')).toBe(210)
expect(group.props('nextMessageId')).toBe(0)
- expect(group.attributes('actorid')).toBe('alice')
- expect(group.attributes('actortype')).toBe(ATTENDEE.ACTOR_TYPE.USERS)
expect(messagesListMock).toHaveBeenCalledWith(TOKEN)
@@ -208,23 +201,11 @@ describe('MessagesList.vue', () => {
const groups = wrapper.findAllComponents({ name: 'MessagesGroup' })
- expect(groups.exists()).toBe(true)
-
- let group = groups.at(0)
- expect(group.props('messages')).toStrictEqual([messages[0]])
- // using attributes to access v-bind props
- expect(group.attributes('actorid')).toBe('alice')
- expect(group.attributes('actortype')).toBe(ATTENDEE.ACTOR_TYPE.USERS)
+ expect(groups.exists()).toBeTruthy()
- group = groups.at(1)
- expect(group.props('messages')).toStrictEqual([messages[1]])
- expect(group.attributes('actorid')).toBe('alice')
- expect(group.attributes('actortype')).toBe(ATTENDEE.ACTOR_TYPE.USERS)
-
- group = groups.at(2)
- expect(group.props('messages')).toStrictEqual([messages[2]])
- expect(group.attributes('actorid')).toBe('alice')
- expect(group.attributes('actortype')).toBe(ATTENDEE.ACTOR_TYPE.USERS)
+ groups.wrappers.forEach((group, index) => {
+ expect(group.props('messages')).toStrictEqual([messages[index]])
+ })
const dateSeparators = wrapper.findAll('.messages-group__date')
expect(dateSeparators).toHaveLength(3)
@@ -279,9 +260,6 @@ describe('MessagesList.vue', () => {
const group = groups.at(0)
expect(group.props('messages')).toStrictEqual(messages)
- // using attributes to access v-bind props
- expect(group.attributes('actorid')).toBe('alice')
- expect(group.attributes('actortype')).toBe(ATTENDEE.ACTOR_TYPE.USERS)
expect(messagesListMock).toHaveBeenCalledWith(TOKEN)
})
@@ -303,12 +281,11 @@ describe('MessagesList.vue', () => {
const groups = wrapper.findAllComponents({ ref: 'messagesGroup' })
- expect(groups.exists()).toBe(true)
+ expect(groups.exists()).toBeTruthy()
- let group = groups.at(0)
- expect(group.props('messages')).toStrictEqual([messages[0]])
- group = groups.at(1)
- expect(group.props('messages')).toStrictE