Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat(messages): Edit messages #11374

Merged
merged 9 commits into from
Jan 17, 2024
15 changes: 13 additions & 2 deletions src/components/ChatView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ import TransitionWrapper from './TransitionWrapper.vue'

import { CONVERSATION } from '../constants.js'
import { EventBus } from '../services/EventBus.js'
import { useChatExtrasStore } from '../stores/chatExtras.js'

export default {

Expand All @@ -108,6 +109,12 @@ export default {
},
},

setup() {
return {
chatExtrasStore: useChatExtrasStore(),
}
},

data() {
return {
isChatScrolledToBottom: true,
Expand All @@ -126,6 +133,10 @@ export default {
return !userName && this.isGuest
},

isEditingMessage() {
return this.chatExtrasStore.getMessageIdToEdit(this.token) !== undefined
},

dropHintText() {
if (this.isGuest) {
return t('spreed', 'You need to be logged in to upload files')
Expand Down Expand Up @@ -155,7 +166,7 @@ export default {
watch: {
container(value) {
this.containerId = value
}
},
},

mounted() {
Expand All @@ -166,7 +177,7 @@ export default {
methods: {

handleDragOver(event) {
if (event.dataTransfer.types.includes('Files')) {
if (event.dataTransfer.types.includes('Files') && !this.isEditingMessage) {
this.isDraggingOver = true
}
},
Expand Down
36 changes: 36 additions & 0 deletions src/components/MessagesList/MessagesGroup/Message/Message.vue
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ the main body of the message as well as a quote.
:sent-icon-tooltip="sentIconTooltip"
@show-translate-dialog="isTranslateDialogOpen = true"
@reply="handleReply"
@edit="handleEdit"
@delete="handleDelete" />
<div v-else-if="showCombinedSystemMessageToggle"
class="message-buttons-bar">
Expand Down Expand Up @@ -407,6 +408,26 @@ export default {
type: String,
default: '',
},

lastEditActorDisplayName: {
type: String,
default: '',
},

lastEditActorId: {
type: String,
default: '',
},

lastEditActorType: {
type: String,
default: '',
},

lastEditTimestamp: {
type: Number,
default: 0,
},
},

emits: ['toggle-combined-system-message'],
Expand Down Expand Up @@ -660,6 +681,10 @@ export default {
containsCodeBlocks() {
return this.message.includes('```')
},

isFileShareOnly() {
return Object.keys(Object(this.messageParameters)).some(key => key.startsWith('file')) && this.message === '{file}'
},
},

watch: {
Expand Down Expand Up @@ -756,6 +781,17 @@ export default {
EventBus.$emit('focus-chat-input')
},

handleEdit() {
this.chatExtrasStore.setMessageIdToEdit(this.token, this.id)
if (this.isFileShareOnly) {
this.chatExtrasStore.setChatEditInput({ token: this.token, text: '' })
} else {
this.chatExtrasStore.setChatEditInput({ token: this.token, text: this.message })
}
EventBus.$emit('editing-message')
EventBus.$emit('focus-chat-input')
},

async handleDelete() {
this.isDeleting = true
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@
@open="onMenuOpen"
@close="onMenuClose">
<template v-if="submenu === null">
<NcActionButton>
<!-- Message timestamp -->
<NcActionText>
<template #icon>
<span v-if="showCommonReadIcon"
:title="commonReadIconTooltip"
Expand All @@ -63,7 +64,20 @@
<ClockOutline v-else :size="16" />
</template>
{{ messageDateTime }}
</NcActionButton>
</NcActionText>
<!-- Edited message timestamp -->
<NcActionButtonGroup v-if="messageObject.lastEditTimestamp">
<NcActionText>
<template #icon>
<ClockEditOutline :size="16" />
</template>
{{ messageObject.lastEditActorDisplayName }}
</NcActionText>
<NcActionText>
{{ editedDateTime }}
</NcActionText>
DorraJaouad marked this conversation as resolved.
Show resolved Hide resolved
</NcActionButtonGroup>
<NcActionSeparator />

<NcActionButton v-if="supportReminders"
class="action--nested"
Expand All @@ -73,8 +87,6 @@
</template>
{{ t('spreed', 'Set reminder') }}
</NcActionButton>

<NcActionSeparator />
<NcActionButton v-if="isPrivateReplyable"
close-after-click
@click.stop="handlePrivateReply">
Expand All @@ -83,6 +95,15 @@
</template>
{{ t('spreed', 'Reply privately') }}
</NcActionButton>
<NcActionButton v-if="isEditable"
:aria-label="t('spreed', 'Edit message')"
close-after-click
@click.stop="editMessage">
<template #icon>
<Pencil :size="20" />
</template>
{{ t('spreed', 'Edit message') }}
</NcActionButton>
<NcActionButton v-if="!isFileShareOnly"
close-after-click
@click.stop="handleCopyMessageText">
Expand Down Expand Up @@ -258,6 +279,7 @@ import ArrowLeft from 'vue-material-design-icons/ArrowLeft.vue'
import CalendarClock from 'vue-material-design-icons/CalendarClock.vue'
import Check from 'vue-material-design-icons/Check.vue'
import CheckAll from 'vue-material-design-icons/CheckAll.vue'
import ClockEditOutline from 'vue-material-design-icons/ClockEditOutline.vue'
import ClockOutline from 'vue-material-design-icons/ClockOutline.vue'
import CloseCircleOutline from 'vue-material-design-icons/CloseCircleOutline.vue'
import ContentCopy from 'vue-material-design-icons/ContentCopy.vue'
Expand All @@ -267,6 +289,7 @@ import EyeOffOutline from 'vue-material-design-icons/EyeOffOutline.vue'
import File from 'vue-material-design-icons/File.vue'
import Note from 'vue-material-design-icons/NoteEditOutline.vue'
import OpenInNewIcon from 'vue-material-design-icons/OpenInNew.vue'
import Pencil from 'vue-material-design-icons/Pencil.vue'
import Plus from 'vue-material-design-icons/Plus.vue'
import Reply from 'vue-material-design-icons/Reply.vue'
import Share from 'vue-material-design-icons/Share.vue'
Expand All @@ -277,10 +300,12 @@ import { showError, showSuccess } from '@nextcloud/dialogs'
import moment from '@nextcloud/moment'

import NcActionButton from '@nextcloud/vue/dist/Components/NcActionButton.js'
import NcActionButtonGroup from '@nextcloud/vue/dist/Components/NcActionButtonGroup.js'
import NcActionInput from '@nextcloud/vue/dist/Components/NcActionInput.js'
import NcActionLink from '@nextcloud/vue/dist/Components/NcActionLink.js'
import NcActions from '@nextcloud/vue/dist/Components/NcActions.js'
import NcActionSeparator from '@nextcloud/vue/dist/Components/NcActionSeparator.js'
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'

Expand All @@ -300,10 +325,12 @@ export default {

components: {
MessageForwarder,
NcActionButtonGroup,
NcActionButton,
NcActionInput,
NcActionLink,
NcActionSeparator,
NcActionText,
NcActions,
NcButton,
NcEmojiPicker,
Expand All @@ -315,6 +342,7 @@ export default {
CloseCircleOutline,
Check,
CheckAll,
ClockEditOutline,
ClockOutline,
ContentCopy,
DeleteIcon,
Expand All @@ -323,6 +351,7 @@ export default {
File,
Note,
OpenInNewIcon,
Pencil,
Plus,
Reply,
Share,
Expand Down Expand Up @@ -447,7 +476,7 @@ export default {
},
},

emits: ['delete', 'update:isActionMenuOpen', 'update:isEmojiPickerOpen', 'update:isReactionsMenuOpen', 'update:isForwarderOpen', 'show-translate-dialog', 'reply'],
emits: ['delete', 'update:isActionMenuOpen', 'update:isEmojiPickerOpen', 'update:isReactionsMenuOpen', 'update:isForwarderOpen', 'show-translate-dialog', 'reply', 'edit'],

setup() {
const reactionsStore = useReactionsStore()
Expand Down Expand Up @@ -482,8 +511,21 @@ export default {
return this.getMessagesListScroller()
},

isModifiable() {
return !this.isConversationReadOnly && this.conversation.participantType !== PARTICIPANT.TYPE.GUEST
},

isEditable() {
if (!this.isModifiable || this.isObjectShare
|| (!this.$store.getters.isModerator && !this.isMyMsg)) {
return false
}

return (moment(this.timestamp * 1000).add(1, 'd')) > moment()
},

isDeleteable() {
if (this.isConversationReadOnly || this.conversation.participantType === PARTICIPANT.TYPE.GUEST) {
if (!this.isModifiable) {
return false
}

Expand Down Expand Up @@ -523,6 +565,10 @@ export default {
return this.isFileShare && this.message === '{file}'
},

isObjectShare() {
return Object.keys(Object(this.messageParameters)).some(key => key.startsWith('object'))
},

isCurrentGuest() {
return this.$store.getters.getActorType() === 'guests'
},
Expand Down Expand Up @@ -560,6 +606,10 @@ export default {
return moment(this.timestamp * 1000).format('lll')
},

editedDateTime() {
return moment(this.messageObject.lastEditTimestamp * 1000).format('lll')
DorraJaouad marked this conversation as resolved.
Show resolved Hide resolved
},

reminderOptions() {
const currentDateTime = moment()

Expand Down Expand Up @@ -791,6 +841,10 @@ export default {
setCustomReminder() {
this.setReminder(this.customReminderDateTime.valueOf())
},

editMessage() {
this.$emit('edit')
},
},
}
</script>
Expand Down
36 changes: 36 additions & 0 deletions src/components/MessagesList/MessagesGroup/MessagesGroup.vue
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@
<ul class="messages">
<li class="messages__author" aria-level="4">
{{ actorDisplayName }}
<div v-if="lastEditActorDisplayName">
{{ getLastEditor }}
</div>
</li>
<Message v-for="(message, index) of messages"
:key="message.id"
Expand Down Expand Up @@ -88,6 +91,24 @@ 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() {
Expand Down Expand Up @@ -133,6 +154,19 @@ export default {
return displayName
},

getLastEditor() {
if (this.lastEditActorId === this.actorId && this.lastEditActorType === this.actorType) {
DorraJaouad marked this conversation as resolved.
Show resolved Hide resolved
// TRANSLATORS Edited by the author of the message themselves
return t('spreed', '(edited)')
DorraJaouad marked this conversation as resolved.
Show resolved Hide resolved
} else if (this.lastEditActorId === this.$store.getters.getActorId()
&& this.lastEditActorType === this.$store.getters.getActorType()) {
return t('spreed', '(edited by you)')
} else {
return t('spreed', '(edited by {moderator})', { moderator: this.lastEditActorDisplayName })
}

},

disableMenu() {
// disable the menu if accessing the conversation as guest
// or the message sender is a bridged user
Expand Down Expand Up @@ -184,6 +218,8 @@ export default {
}

&__author {
display: flex;
gap: 4px;
padding: 4px 0 0 8px;
color: var(--color-text-maxcontrast);
}
Expand Down
Loading
Loading