mirror of
https://github.com/lingble/chatwoot.git
synced 2025-11-01 11:37:58 +00:00
chore: Refactor messages to support right click context menu (#6748)
This commit is contained in:
@@ -21,8 +21,8 @@ class MessageFinder
|
||||
end
|
||||
|
||||
def current_messages
|
||||
if @params[:after].present?
|
||||
messages.reorder('created_at asc').where('id >= ?', @params[:before].to_i).limit(20)
|
||||
if @params[:after].present? && @params[:before].present?
|
||||
messages.reorder('created_at asc').where('id >= ? AND id < ?', @params[:after].to_i, @params[:before].to_i).limit(1000)
|
||||
elsif @params[:before].present?
|
||||
messages.reorder('created_at desc').where('id < ?', @params[:before].to_i).limit(20).reverse
|
||||
else
|
||||
|
||||
@@ -75,10 +75,12 @@ class MessageApi extends ApiClient {
|
||||
return axios.delete(`${this.url}/${conversationID}/messages/${messageId}`);
|
||||
}
|
||||
|
||||
getPreviousMessages({ conversationId, before }) {
|
||||
return axios.get(`${this.url}/${conversationId}/messages`, {
|
||||
params: { before },
|
||||
});
|
||||
getPreviousMessages({ conversationId, after, before }) {
|
||||
const params = { before };
|
||||
if (after && Number(after) !== Number(before)) {
|
||||
params.after = after;
|
||||
}
|
||||
return axios.get(`${this.url}/${conversationId}/messages`, { params });
|
||||
}
|
||||
|
||||
translateMessage(conversationId, messageId, targetLanguage) {
|
||||
|
||||
@@ -73,39 +73,12 @@
|
||||
:created-at="createdAt"
|
||||
/>
|
||||
</div>
|
||||
<woot-modal
|
||||
<translate-modal
|
||||
v-if="showTranslateModal"
|
||||
modal-type="right-aligned"
|
||||
show
|
||||
:on-close="onCloseTranslateModal"
|
||||
>
|
||||
<div class="column content">
|
||||
<p>
|
||||
<b>{{ $t('TRANSLATE_MODAL.ORIGINAL_CONTENT') }}</b>
|
||||
</p>
|
||||
<p v-dompurify-html="data.content" />
|
||||
<br />
|
||||
<hr />
|
||||
<div v-if="translationsAvailable">
|
||||
<p>
|
||||
<b>{{ $t('TRANSLATE_MODAL.TRANSLATED_CONTENT') }}</b>
|
||||
</p>
|
||||
<div
|
||||
v-for="(translation, language) in translations"
|
||||
:key="language"
|
||||
>
|
||||
<p>
|
||||
<strong>{{ language }}:</strong>
|
||||
</p>
|
||||
<p v-dompurify-html="translation" />
|
||||
<br />
|
||||
</div>
|
||||
</div>
|
||||
<p v-else>
|
||||
{{ $t('TRANSLATE_MODAL.NO_TRANSLATIONS_AVAILABLE') }}
|
||||
</p>
|
||||
</div>
|
||||
</woot-modal>
|
||||
:content="data.content"
|
||||
:content-attributes="contentAttributes"
|
||||
@close="onCloseTranslateModal"
|
||||
/>
|
||||
<spinner v-if="isPending" size="tiny" />
|
||||
<div
|
||||
v-if="showAvatar"
|
||||
@@ -173,6 +146,7 @@ import contentTypeMixin from 'shared/mixins/contentTypeMixin';
|
||||
import { MESSAGE_TYPE, MESSAGE_STATUS } from 'shared/constants/messages';
|
||||
import { generateBotMessageContent } from './helpers/botMessageContentHelper';
|
||||
import { mapGetters } from 'vuex';
|
||||
import TranslateModal from './bubble/TranslateModal.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@@ -188,6 +162,7 @@ export default {
|
||||
ContextMenu,
|
||||
Spinner,
|
||||
instagramImageErrorPlaceholder,
|
||||
TranslateModal,
|
||||
},
|
||||
mixins: [alertMixin, messageFormatterMixin, contentTypeMixin],
|
||||
props: {
|
||||
@@ -239,9 +214,6 @@ export default {
|
||||
} = this.contentAttributes.email || {};
|
||||
return fullHTMLContent || fullTextContent || '';
|
||||
},
|
||||
translations() {
|
||||
return this.contentAttributes.translations || {};
|
||||
},
|
||||
displayQuotedButton() {
|
||||
if (this.emailMessageContent.includes('<blockquote')) {
|
||||
return true;
|
||||
@@ -253,9 +225,6 @@ export default {
|
||||
|
||||
return false;
|
||||
},
|
||||
translationsAvailable() {
|
||||
return !!Object.keys(this.translations).length;
|
||||
},
|
||||
message() {
|
||||
// If the message is an email, emailMessageContent would be present
|
||||
// In that case, we would use letter package to render the email
|
||||
@@ -612,18 +581,10 @@ export default {
|
||||
margin-top: var(--space-smaller) var(--space-smaller) 0 0;
|
||||
}
|
||||
|
||||
.button--delete-message {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
li.left,
|
||||
li.right {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
|
||||
&:hover .button--delete-message {
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
|
||||
li.left.has-tweet-menu .context-menu {
|
||||
@@ -652,9 +613,6 @@ li.right {
|
||||
|
||||
.has-context-menu {
|
||||
background: var(--color-background);
|
||||
.button--delete-message {
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
|
||||
.context-menu {
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
<template>
|
||||
<woot-modal
|
||||
modal-type="right-aligned"
|
||||
class="text-left"
|
||||
show
|
||||
:on-close="onClose"
|
||||
>
|
||||
<div class="column content">
|
||||
<p>
|
||||
<b>{{ $t('TRANSLATE_MODAL.ORIGINAL_CONTENT') }}</b>
|
||||
</p>
|
||||
<p v-dompurify-html="content" />
|
||||
<br />
|
||||
<hr />
|
||||
<div v-if="translationsAvailable">
|
||||
<p>
|
||||
<b>{{ $t('TRANSLATE_MODAL.TRANSLATED_CONTENT') }}</b>
|
||||
</p>
|
||||
<div v-for="(translation, language) in translations" :key="language">
|
||||
<p>
|
||||
<strong>{{ language }}:</strong>
|
||||
</p>
|
||||
<p v-dompurify-html="translation" />
|
||||
<br />
|
||||
</div>
|
||||
</div>
|
||||
<p v-else>
|
||||
{{ $t('TRANSLATE_MODAL.NO_TRANSLATIONS_AVAILABLE') }}
|
||||
</p>
|
||||
</div>
|
||||
</woot-modal>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
contentAttributes: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
content: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
translationsAvailable() {
|
||||
return !!Object.keys(this.translations).length;
|
||||
},
|
||||
translations() {
|
||||
return this.contentAttributes.translations || {};
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
onClose() {
|
||||
this.$emit('close');
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="menu" @click.stop="$emit('click')">
|
||||
<div class="menu" role="button" @click.stop="$emit('click')">
|
||||
<fluent-icon
|
||||
v-if="variant === 'icon' && option.icon"
|
||||
:icon="option.icon"
|
||||
|
||||
@@ -83,7 +83,7 @@ export default {
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
opacity: 50%;
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ const actions = {
|
||||
id: data.conversationId,
|
||||
data: payload,
|
||||
});
|
||||
if (payload.length < 20) {
|
||||
if (!payload.length) {
|
||||
commit(types.SET_ALL_MESSAGES_LOADED);
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -217,9 +217,7 @@ const actions = {
|
||||
{ conversationId, messageId }
|
||||
) {
|
||||
try {
|
||||
const response = await MessageApi.delete(conversationId, messageId);
|
||||
const { data } = response;
|
||||
// The delete message is actually deleting the content.
|
||||
const { data } = await MessageApi.delete(conversationId, messageId);
|
||||
commit(types.ADD_MESSAGE, data);
|
||||
} catch (error) {
|
||||
throw new Error(error);
|
||||
|
||||
Reference in New Issue
Block a user