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