From 613fb0b06425fd61d4808375c0ab019c13cc1ca6 Mon Sep 17 00:00:00 2001
From: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
Date: Mon, 5 Dec 2022 11:16:00 +0530
Subject: [PATCH 01/48] fix: Unable to add emoji exactly where the cursor is at
(#5865)
* fix: Unable to add emoji exactly where the cursor is at
* chore: Minor fixes
* chore: Review fixes
* chore: Code clean up
* chore: Review fixes
* chore: Minor fixes
* chore: Review fixes
---
.../components/widgets/WootWriter/Editor.vue | 20 ++++++++++++++++
.../widgets/conversation/ReplyBox.vue | 23 ++++++++++++++++++-
2 files changed, 42 insertions(+), 1 deletion(-)
diff --git a/app/javascript/dashboard/components/widgets/WootWriter/Editor.vue b/app/javascript/dashboard/components/widgets/WootWriter/Editor.vue
index a00a3bf5a..bd47074ce 100644
--- a/app/javascript/dashboard/components/widgets/WootWriter/Editor.vue
+++ b/app/javascript/dashboard/components/widgets/WootWriter/Editor.vue
@@ -65,6 +65,7 @@ export default {
placeholder: { type: String, default: '' },
isPrivate: { type: Boolean, default: false },
enableSuggestions: { type: Boolean, default: true },
+ updateSelectionWith: { type: String, default: '' },
},
data() {
return {
@@ -162,6 +163,25 @@ export default {
isPrivate() {
this.reloadState();
},
+
+ updateSelectionWith(newValue, oldValue) {
+ if (!this.editorView) {
+ return null;
+ }
+ if (newValue !== oldValue) {
+ if (this.updateSelectionWith !== '') {
+ const node = this.editorView.state.schema.text(
+ this.updateSelectionWith
+ );
+ const tr = this.editorView.state.tr.replaceSelectionWith(node);
+ this.editorView.focus();
+ this.state = this.editorView.state.apply(tr);
+ this.emitOnChange();
+ this.$emit('clear-selection');
+ }
+ }
+ return null;
+ },
},
created() {
this.state = createState(this.value, this.placeholder, this.plugins);
diff --git a/app/javascript/dashboard/components/widgets/conversation/ReplyBox.vue b/app/javascript/dashboard/components/widgets/conversation/ReplyBox.vue
index e7c825752..fdbb2fbdd 100644
--- a/app/javascript/dashboard/components/widgets/conversation/ReplyBox.vue
+++ b/app/javascript/dashboard/components/widgets/conversation/ReplyBox.vue
@@ -60,6 +60,7 @@
class="input"
:is-private="isOnPrivateNote"
:placeholder="messagePlaceHolder"
+ :update-selection-with="updateEditorSelectionWith"
:min-height="4"
@typing-off="onTypingOff"
@typing-on="onTypingOn"
@@ -67,6 +68,7 @@
@blur="onBlur"
@toggle-user-mention="toggleUserMention"
@toggle-canned-menu="toggleCannedMenu"
+ @clear-selection="clearEditorSelection"
/>
@@ -215,6 +217,7 @@ export default {
ccEmails: '',
doAutoSaveDraft: () => {},
showWhatsAppTemplatesModal: false,
+ updateEditorSelectionWith: '',
};
},
computed: {
@@ -707,8 +710,26 @@ export default {
}
this.$nextTick(() => this.$refs.messageInput.focus());
},
+ clearEditorSelection() {
+ this.updateEditorSelectionWith = '';
+ },
+ insertEmoji(emoji, selectionStart, selectionEnd) {
+ const { message } = this;
+ const newMessage =
+ message.slice(0, selectionStart) +
+ emoji +
+ message.slice(selectionEnd, message.length);
+ this.message = newMessage;
+ },
emojiOnClick(emoji) {
- this.message = `${this.message}${emoji} `;
+ if (this.showRichContentEditor) {
+ this.updateEditorSelectionWith = emoji;
+ this.onFocus();
+ }
+ if (!this.showRichContentEditor) {
+ const { selectionStart, selectionEnd } = this.$refs.messageInput.$el;
+ this.insertEmoji(emoji, selectionStart, selectionEnd);
+ }
},
clearMessage() {
this.message = '';
From c9cae01cb47213de9394055bbabbffd525c7859a Mon Sep 17 00:00:00 2001
From: Muhsin Keloth
Date: Mon, 5 Dec 2022 12:30:56 +0530
Subject: [PATCH 02/48] fix: Support audio in safari browser (#5943)
---
.../widgets/WootWriter/AudioRecorder.vue | 34 +++++++++++++++----
.../widgets/WootWriter/ReplyBottomPanel.vue | 9 ++++-
app/javascript/shared/constants/messages.js | 5 +++
3 files changed, 40 insertions(+), 8 deletions(-)
diff --git a/app/javascript/dashboard/components/widgets/WootWriter/AudioRecorder.vue b/app/javascript/dashboard/components/widgets/WootWriter/AudioRecorder.vue
index 893bdcf3a..9c53d4a1a 100644
--- a/app/javascript/dashboard/components/widgets/WootWriter/AudioRecorder.vue
+++ b/app/javascript/dashboard/components/widgets/WootWriter/AudioRecorder.vue
@@ -23,6 +23,7 @@ import 'videojs-wavesurfer/dist/videojs.wavesurfer.js';
import 'videojs-record/dist/videojs.record.js';
import 'videojs-record/dist/plugins/videojs.record.opus-recorder.js';
import { format, addSeconds } from 'date-fns';
+import { AUDIO_FORMATS } from 'shared/constants/messages';
WaveSurfer.microphone = MicrophonePlugin;
@@ -70,13 +71,26 @@ export default {
record: {
audio: true,
video: false,
- displayMilliseconds: false,
- maxLength: 300,
- audioEngine: 'opus-recorder',
- audioWorkerURL: encoderWorker,
- audioChannels: 1,
- audioSampleRate: 48000,
- audioBitRate: 128,
+ ...(this.audioRecordFormat === AUDIO_FORMATS.WEBM && {
+ monitorGain: 0,
+ recordingGain: 1,
+ numberOfChannels: 1,
+ encoderSampleRate: 16000,
+ originalSampleRateOverride: 16000,
+ streamPages: true,
+ maxFramesPerPage: 1,
+ encoderFrameSize: 1,
+ encoderPath: 'opus-recorder/dist/waveWorker.min.js',
+ }),
+ ...(this.audioRecordFormat === AUDIO_FORMATS.OGG && {
+ displayMilliseconds: false,
+ maxLength: 300,
+ audioEngine: 'opus-recorder',
+ audioWorkerURL: encoderWorker,
+ audioChannels: 1,
+ audioSampleRate: 48000,
+ audioBitRate: 128,
+ }),
},
},
},
@@ -86,6 +100,12 @@ export default {
isRecording() {
return this.player && this.player.record().isRecording();
},
+ audioRecordFormat() {
+ if (this.isAWebWidgetInbox) {
+ return AUDIO_FORMATS.WEBM;
+ }
+ return AUDIO_FORMATS.OGG;
+ },
},
mounted() {
window.Recorder = Recorder;
diff --git a/app/javascript/dashboard/components/widgets/WootWriter/ReplyBottomPanel.vue b/app/javascript/dashboard/components/widgets/WootWriter/ReplyBottomPanel.vue
index a8c26201e..bd67011e5 100644
--- a/app/javascript/dashboard/components/widgets/WootWriter/ReplyBottomPanel.vue
+++ b/app/javascript/dashboard/components/widgets/WootWriter/ReplyBottomPanel.vue
@@ -232,11 +232,18 @@ export default {
return this.showFileUpload || this.isNote;
},
showAudioRecorderButton() {
+ // Disable audio recorder for safari browser as recording is not supported
+ const isSafari = /^((?!chrome|android|crios|fxios).)*safari/i.test(
+ navigator.userAgent
+ );
+
return (
this.isFeatureEnabledonAccount(
this.accountId,
FEATURE_FLAGS.VOICE_RECORDER
- ) && this.showAudioRecorder
+ ) &&
+ this.showAudioRecorder &&
+ !isSafari
);
},
showAudioPlayStopButton() {
diff --git a/app/javascript/shared/constants/messages.js b/app/javascript/shared/constants/messages.js
index e189a19a8..70235ce0e 100644
--- a/app/javascript/shared/constants/messages.js
+++ b/app/javascript/shared/constants/messages.js
@@ -72,3 +72,8 @@ export const CSAT_RATINGS = [
color: '#44CE4B',
},
];
+
+export const AUDIO_FORMATS = {
+ WEBM: 'audio/webm',
+ OGG: 'audio/ogg',
+};
From c3b6e1a732faab67feee143bb07caa12c6e4af16 Mon Sep 17 00:00:00 2001
From: Vishnu Narayanan
Date: Mon, 5 Dec 2022 21:15:44 +0530
Subject: [PATCH 03/48] fix: update heroku app.json to use premium plans
(#5349)
* fix: update heroku app.json to use premium plans
Use premium/paid dynos and addons as Heroku is set to deprecate free dynos/addons.
* fix: set default stack to heroku-20
* chore: update heroku app.json to use new dyno types
web and worker to use basic dynos
redis and postgres to use mini
---
app.json | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/app.json b/app.json
index 055235032..6324672fb 100644
--- a/app.json
+++ b/app.json
@@ -41,16 +41,24 @@
"formation": {
"web": {
"quantity": 1,
- "size": "FREE"
+ "size": "basic"
},
"worker": {
"quantity": 1,
- "size": "FREE"
+ "size": "basic"
}
},
"stack": "heroku-20",
"image": "heroku/ruby",
- "addons": [ "heroku-redis", "heroku-postgresql"],
+ "addons": [
+ {
+ "plan": "heroku-redis:mini"
+ },
+ {
+ "plan": "heroku-postgresql:mini"
+ }
+ ],
+ "stack": "heroku-20",
"buildpacks": [
{
"url": "heroku/ruby"
From 87ef39ad9cc45e53f38c2c385ccc51689a9b9bae Mon Sep 17 00:00:00 2001
From: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
Date: Tue, 6 Dec 2022 05:30:42 +0530
Subject: [PATCH 04/48] feat: Add the ability to search emojis (#5928)
---
.../widgets/conversation/MessagesView.vue | 7 +-
.../widgets/conversation/ReplyBox.vue | 13 +-
.../dashboard/i18n/locale/en/emoji.json | 6 +
.../dashboard/i18n/locale/en/index.js | 6 +-
.../shared/components/emoji/EmojiInput.vue | 268 +-
.../shared/components/emoji/emojis.json | 1 -
.../shared/components/emoji/emojisGroup.json | 9291 +++++++++++++++++
.../widget/components/ChatInputWrap.vue | 7 +-
app/javascript/widget/i18n/locale/en.json | 4 +
9 files changed, 9529 insertions(+), 74 deletions(-)
create mode 100644 app/javascript/dashboard/i18n/locale/en/emoji.json
delete mode 100644 app/javascript/shared/components/emoji/emojis.json
create mode 100644 app/javascript/shared/components/emoji/emojisGroup.json
diff --git a/app/javascript/dashboard/components/widgets/conversation/MessagesView.vue b/app/javascript/dashboard/components/widgets/conversation/MessagesView.vue
index 0ebe35465..9df60200e 100644
--- a/app/javascript/dashboard/components/widgets/conversation/MessagesView.vue
+++ b/app/javascript/dashboard/components/widgets/conversation/MessagesView.vue
@@ -433,12 +433,7 @@ export default {
position: fixed;
left: unset;
position: absolute;
-
- &::before {
- transform: rotate(0deg);
- left: var(--space-smaller);
- bottom: var(--space-minus-slab);
- }
+ bottom: var(--space-smaller);
}
}
}
diff --git a/app/javascript/dashboard/components/widgets/conversation/ReplyBox.vue b/app/javascript/dashboard/components/widgets/conversation/ReplyBox.vue
index fdbb2fbdd..e8326fed0 100644
--- a/app/javascript/dashboard/components/widgets/conversation/ReplyBox.vue
+++ b/app/javascript/dashboard/components/widgets/conversation/ReplyBox.vue
@@ -132,7 +132,6 @@ import { mapGetters } from 'vuex';
import { mixin as clickaway } from 'vue-clickaway';
import alertMixin from 'shared/mixins/alertMixin';
-import EmojiInput from 'shared/components/emoji/EmojiInput';
import CannedResponse from './CannedResponse';
import ResizableTextArea from 'shared/components/ResizableTextArea';
import AttachmentPreview from 'dashboard/components/widgets/AttachmentsPreview';
@@ -163,6 +162,8 @@ import { trimContent, debounce } from '@chatwoot/utils';
import wootConstants from 'dashboard/constants';
import { isEditorHotKeyEnabled } from 'dashboard/mixins/uiSettings';
+const EmojiInput = () => import('shared/components/emoji/EmojiInput');
+
export default {
components: {
EmojiInput,
@@ -401,7 +402,7 @@ export default {
return conversationDisplayType !== CONDENSED;
},
emojiDialogClassOnExpanedLayout() {
- return this.isOnExpandedLayout && !this.popoutReplyBox
+ return this.isOnExpandedLayout || this.popoutReplyBox
? 'emoji-dialog--expanded'
: '';
},
@@ -984,13 +985,13 @@ export default {
.emoji-dialog {
top: unset;
- bottom: 12px;
+ bottom: var(--space-normal);
left: -320px;
right: unset;
&::before {
- right: -16px;
- bottom: 10px;
+ right: var(--space-minus-normal);
+ bottom: var(--space-small);
transform: rotate(270deg);
filter: drop-shadow(0px 4px 4px rgba(0, 0, 0, 0.08));
}
@@ -1004,7 +1005,7 @@ export default {
&::before {
transform: rotate(0deg);
left: var(--space-smaller);
- bottom: var(--space-minus-slab);
+ bottom: var(--space-minus-small);
}
}
.message-signature {
diff --git a/app/javascript/dashboard/i18n/locale/en/emoji.json b/app/javascript/dashboard/i18n/locale/en/emoji.json
new file mode 100644
index 000000000..fd81268fb
--- /dev/null
+++ b/app/javascript/dashboard/i18n/locale/en/emoji.json
@@ -0,0 +1,6 @@
+{
+ "EMOJI": {
+ "PLACEHOLDER": "Search emojis",
+ "NOT_FOUND": "No emoji match your search"
+ }
+}
diff --git a/app/javascript/dashboard/i18n/locale/en/index.js b/app/javascript/dashboard/i18n/locale/en/index.js
index 93e560119..0c674eef2 100644
--- a/app/javascript/dashboard/i18n/locale/en/index.js
+++ b/app/javascript/dashboard/i18n/locale/en/index.js
@@ -10,7 +10,8 @@ import chatlist from './chatlist.json';
import contact from './contact.json';
import contactFilters from './contactFilters.json';
import conversation from './conversation.json';
-import csatMgmtMgmt from './csatMgmt.json';
+import csatMgmt from './csatMgmt.json';
+import emoji from './emoji.json';
import generalSettings from './generalSettings.json';
import helpCenter from './helpCenter.json';
import inboxMgmt from './inboxMgmt.json';
@@ -40,7 +41,8 @@ export default {
...contact,
...contactFilters,
...conversation,
- ...csatMgmtMgmt,
+ ...csatMgmt,
+ ...emoji,
...generalSettings,
...helpCenter,
...inboxMgmt,
diff --git a/app/javascript/shared/components/emoji/EmojiInput.vue b/app/javascript/shared/components/emoji/EmojiInput.vue
index 84891b0e2..32d9c3df1 100644
--- a/app/javascript/shared/components/emoji/EmojiInput.vue
+++ b/app/javascript/shared/components/emoji/EmojiInput.vue
@@ -1,41 +1,92 @@
-