From c9f821cc5b6768456192d12520acbc839ddb4b7a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 31 Mar 2022 16:02:53 +0530 Subject: [PATCH 01/20] chore(deps): bump puma from 5.6.2 to 5.6.4 (#4348) Bumps [puma](https://github.com/puma/puma) from 5.6.2 to 5.6.4. - [Release notes](https://github.com/puma/puma/releases) - [Changelog](https://github.com/puma/puma/blob/master/History.md) - [Commits](https://github.com/puma/puma/compare/v5.6.2...v5.6.4) --- updated-dependencies: - dependency-name: puma dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index eb6022ac7..6c314817d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -403,7 +403,7 @@ GEM pry-rails (0.3.9) pry (>= 0.10.4) public_suffix (4.0.6) - puma (5.6.2) + puma (5.6.4) nio4r (~> 2.0) pundit (2.2.0) activesupport (>= 3.0.0) From 0477123f92234c7e1e060ce5e190f90eac0af9a8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 31 Mar 2022 16:33:14 +0530 Subject: [PATCH 02/20] chore(deps): bump minimist from 1.2.5 to 1.2.6 (#4351) Bumps [minimist](https://github.com/substack/minimist) from 1.2.5 to 1.2.6. - [Release notes](https://github.com/substack/minimist/releases) - [Commits](https://github.com/substack/minimist/compare/1.2.5...1.2.6) --- updated-dependencies: - dependency-name: minimist dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 931d979a6..9acb20d6a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10090,9 +10090,9 @@ minimatch@3.0.4, minimatch@^3.0.2, minimatch@^3.0.4: brace-expansion "^1.1.7" minimist@^1.1.1, minimist@^1.2.0, minimist@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" - integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== + version "1.2.6" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" + integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== minipass-collect@^1.0.2: version "1.0.2" From eff3a5031641b4b655806109315b1ea52f342588 Mon Sep 17 00:00:00 2001 From: Muhsin Keloth Date: Thu, 31 Mar 2022 17:35:39 +0530 Subject: [PATCH 03/20] fix: Disable showing read messages in unread view (#4324) --- app/javascript/widget/App.vue | 9 +++++- .../store/modules/conversation/actions.js | 8 ++++-- .../specs/conversation/actions.spec.js | 28 +++++++++++-------- .../v1/widget/messages/index.json.jbuilder | 25 ++++++++++------- .../api/v1/widget/messages_controller_spec.rb | 3 +- 5 files changed, 47 insertions(+), 26 deletions(-) diff --git a/app/javascript/widget/App.vue b/app/javascript/widget/App.vue index 8b34c51bf..9d6600264 100755 --- a/app/javascript/widget/App.vue +++ b/app/javascript/widget/App.vue @@ -138,7 +138,13 @@ export default { } }, registerUnreadEvents() { - bus.$on(ON_AGENT_MESSAGE_RECEIVED, this.setUnreadView); + bus.$on(ON_AGENT_MESSAGE_RECEIVED, () => { + const { name: routeName } = this.$route; + if (this.isWidgetOpen && routeName === 'messages') { + this.$store.dispatch('conversation/setUserLastSeen'); + } + this.setUnreadView(); + }); bus.$on(ON_UNREAD_MESSAGE_CLICK, () => { this.replaceRoute('messages').then(() => this.unsetUnreadView()); }); @@ -175,6 +181,7 @@ export default { }, setUnreadView() { const { unreadMessageCount } = this; + if (this.isIFrame && unreadMessageCount > 0 && !this.isWidgetOpen) { this.replaceRoute('unread-messages').then(() => { this.setIframeHeight(true); diff --git a/app/javascript/widget/store/modules/conversation/actions.js b/app/javascript/widget/store/modules/conversation/actions.js index c915ea6e7..ae06afa9c 100644 --- a/app/javascript/widget/store/modules/conversation/actions.js +++ b/app/javascript/widget/store/modules/conversation/actions.js @@ -84,8 +84,12 @@ export const actions = { fetchOldConversations: async ({ commit }, { before } = {}) => { try { commit('setConversationListLoading', true); - const { data } = await getMessagesAPI({ before }); - const formattedMessages = getNonDeletedMessages({ messages: data }); + const { + data: { payload, meta }, + } = await getMessagesAPI({ before }); + const { contact_last_seen_at: lastSeen } = meta; + const formattedMessages = getNonDeletedMessages({ messages: payload }); + commit('conversation/setMetaUserLastSeenAt', lastSeen, { root: true }); commit('setMessagesInConversation', formattedMessages); commit('setConversationListLoading', false); } catch (error) { diff --git a/app/javascript/widget/store/modules/specs/conversation/actions.spec.js b/app/javascript/widget/store/modules/specs/conversation/actions.spec.js index cfbb0ec66..82e03d38a 100644 --- a/app/javascript/widget/store/modules/specs/conversation/actions.spec.js +++ b/app/javascript/widget/store/modules/specs/conversation/actions.spec.js @@ -181,22 +181,28 @@ describe('#actions', () => { describe('#fetchOldConversations', () => { it('sends correct actions', async () => { API.get.mockResolvedValue({ - data: [ - { - id: 1, - text: 'hey', - content_attributes: {}, + data: { + payload: [ + { + id: 1, + text: 'hey', + content_attributes: {}, + }, + { + id: 2, + text: 'welcome', + content_attributes: { deleted: true }, + }, + ], + meta: { + contact_last_seen_at: 1466424490, }, - { - id: 2, - text: 'welcome', - content_attributes: { deleted: true }, - }, - ], + }, }); await actions.fetchOldConversations({ commit }, {}); expect(commit.mock.calls).toEqual([ ['setConversationListLoading', true], + ['conversation/setMetaUserLastSeenAt', 1466424490, { root: true }], [ 'setMessagesInConversation', [ diff --git a/app/views/api/v1/widget/messages/index.json.jbuilder b/app/views/api/v1/widget/messages/index.json.jbuilder index a0462b545..d7a441b84 100644 --- a/app/views/api/v1/widget/messages/index.json.jbuilder +++ b/app/views/api/v1/widget/messages/index.json.jbuilder @@ -1,11 +1,16 @@ -json.array! @messages do |message| - json.id message.id - json.content message.content - json.message_type message.message_type_before_type_cast - json.content_type message.content_type - json.content_attributes message.content_attributes - json.created_at message.created_at.to_i - json.conversation_id message.conversation.display_id - json.attachments message.attachments.map(&:push_event_data) if message.attachments.present? - json.sender message.sender.push_event_data if message.sender +json.payload do + json.array! @messages do |message| + json.id message.id + json.content message.content + json.message_type message.message_type_before_type_cast + json.content_type message.content_type + json.content_attributes message.content_attributes + json.created_at message.created_at.to_i + json.conversation_id message.conversation.display_id + json.attachments message.attachments.map(&:push_event_data) if message.attachments.present? + json.sender message.sender.push_event_data if message.sender + end +end +json.meta do + json.contact_last_seen_at @conversation.contact_last_seen_at.to_i end diff --git a/spec/controllers/api/v1/widget/messages_controller_spec.rb b/spec/controllers/api/v1/widget/messages_controller_spec.rb index 983f6f132..f203f11c8 100644 --- a/spec/controllers/api/v1/widget/messages_controller_spec.rb +++ b/spec/controllers/api/v1/widget/messages_controller_spec.rb @@ -23,9 +23,8 @@ RSpec.describe '/api/v1/widget/messages', type: :request do expect(response).to have_http_status(:success) json_response = JSON.parse(response.body) - # 2 messages created + 2 messages by the email hook - expect(json_response.length).to eq(4) + expect(json_response['payload'].length).to eq(4) end end end From 3cd1616df624f25205c338398466e978fcee0db9 Mon Sep 17 00:00:00 2001 From: Sivin Varghese <64252451+iamsivin@users.noreply.github.com> Date: Thu, 31 Mar 2022 20:22:52 +0530 Subject: [PATCH 04/20] fix: Fix agent name in Twitter channel private note acting as a link (#4326) --- .../widgets/conversation/Message.vue | 6 +++- .../shared/helpers/MessageFormatter.js | 5 ++-- .../helpers/specs/MessageFormatter.spec.js | 30 +++++++++++++++++-- .../shared/mixins/messageFormatterMixin.js | 8 +++-- 4 files changed, 42 insertions(+), 7 deletions(-) diff --git a/app/javascript/dashboard/components/widgets/conversation/Message.vue b/app/javascript/dashboard/components/widgets/conversation/Message.vue index 51d82ff8c..4035a62d0 100644 --- a/app/javascript/dashboard/components/widgets/conversation/Message.vue +++ b/app/javascript/dashboard/components/widgets/conversation/Message.vue @@ -207,7 +207,11 @@ export default { } } return ( - this.formatMessage(this.data.content, this.isATweet) + botMessageContent + this.formatMessage( + this.data.content, + this.isATweet, + this.data.private + ) + botMessageContent ); }, contentAttributes() { diff --git a/app/javascript/shared/helpers/MessageFormatter.js b/app/javascript/shared/helpers/MessageFormatter.js index 3bc89ec2f..260436da4 100644 --- a/app/javascript/shared/helpers/MessageFormatter.js +++ b/app/javascript/shared/helpers/MessageFormatter.js @@ -13,8 +13,9 @@ const TWITTER_HASH_REPLACEMENT = const USER_MENTIONS_REGEX = /mention:\/\/(user|team)\/(\d+)\/(.+)/gm; class MessageFormatter { - constructor(message, isATweet = false) { + constructor(message, isATweet = false, isAPrivateNote = false) { this.message = DOMPurify.sanitize(escapeHtml(message || '')); + this.isAPrivateNote = isAPrivateNote; this.isATweet = isATweet; this.marked = marked; @@ -35,7 +36,7 @@ class MessageFormatter { } formatMessage() { - if (this.isATweet) { + if (this.isATweet && !this.isAPrivateNote) { const withUserName = this.message.replace( TWITTER_USERNAME_REGEX, TWITTER_USERNAME_REPLACEMENT diff --git a/app/javascript/shared/helpers/specs/MessageFormatter.spec.js b/app/javascript/shared/helpers/specs/MessageFormatter.spec.js index 4e13fe832..1f2209b71 100644 --- a/app/javascript/shared/helpers/specs/MessageFormatter.spec.js +++ b/app/javascript/shared/helpers/specs/MessageFormatter.spec.js @@ -36,19 +36,45 @@ describe('#MessageFormatter', () => { it('should add links to @mentions', () => { const message = '@chatwootapp is an opensource tool thanks @longnonexistenttwitterusername'; - expect(new MessageFormatter(message, true).formattedMessage).toMatch( + expect( + new MessageFormatter(message, true, false).formattedMessage + ).toMatch( '

@chatwootapp is an opensource tool thanks @longnonexistenttwitterusername

' ); }); it('should add links to #tags', () => { const message = '#chatwootapp is an opensource tool'; - expect(new MessageFormatter(message, true).formattedMessage).toMatch( + expect( + new MessageFormatter(message, true, false).formattedMessage + ).toMatch( '

#chatwootapp is an opensource tool

' ); }); }); + describe('private notes', () => { + it('should return the same string if not tags or @mentions', () => { + const message = 'Chatwoot is an opensource tool'; + expect(new MessageFormatter(message).formattedMessage).toMatch(message); + }); + + it('should add links to @mentions', () => { + const message = + '@chatwootapp is an opensource tool thanks @longnonexistenttwitterusername'; + expect( + new MessageFormatter(message, false, true).formattedMessage + ).toMatch(message); + }); + + it('should add links to #tags', () => { + const message = '#chatwootapp is an opensource tool'; + expect( + new MessageFormatter(message, false, true).formattedMessage + ).toMatch(message); + }); + }); + describe('plain text content', () => { it('returns the plain text without HTML', () => { const message = diff --git a/app/javascript/shared/mixins/messageFormatterMixin.js b/app/javascript/shared/mixins/messageFormatterMixin.js index 21096409d..7767e7c76 100644 --- a/app/javascript/shared/mixins/messageFormatterMixin.js +++ b/app/javascript/shared/mixins/messageFormatterMixin.js @@ -3,8 +3,12 @@ import DOMPurify from 'dompurify'; export default { methods: { - formatMessage(message, isATweet) { - const messageFormatter = new MessageFormatter(message, isATweet); + formatMessage(message, isATweet, isAPrivateNote) { + const messageFormatter = new MessageFormatter( + message, + isATweet, + isAPrivateNote + ); return messageFormatter.formattedMessage; }, getPlainText(message, isATweet) { From cb23ff53bf7f1b190223b13aedbfefcb7c4ec85f Mon Sep 17 00:00:00 2001 From: Sivin Varghese <64252451+iamsivin@users.noreply.github.com> Date: Thu, 31 Mar 2022 21:20:37 +0530 Subject: [PATCH 05/20] fix: Reset Captcha if account signup is an error (#4279) Co-authored-by: Pranav Raj S --- .../conversation/AvailabilityStatusBadge.vue | 2 +- .../i18n/locale/en/setNewPassword.json | 3 ++ .../dashboard/routes/auth/Signup.vue | 32 +++++++++++++++++++ 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/app/javascript/dashboard/components/widgets/conversation/AvailabilityStatusBadge.vue b/app/javascript/dashboard/components/widgets/conversation/AvailabilityStatusBadge.vue index 588bbef82..766166fd3 100644 --- a/app/javascript/dashboard/components/widgets/conversation/AvailabilityStatusBadge.vue +++ b/app/javascript/dashboard/components/widgets/conversation/AvailabilityStatusBadge.vue @@ -23,7 +23,7 @@ export default { background: var(--s-500); } &__busy { - background: var(--y-700); + background: var(--y-400); } } diff --git a/app/javascript/dashboard/i18n/locale/en/setNewPassword.json b/app/javascript/dashboard/i18n/locale/en/setNewPassword.json index 94a3fd2e1..ec2d94744 100644 --- a/app/javascript/dashboard/i18n/locale/en/setNewPassword.json +++ b/app/javascript/dashboard/i18n/locale/en/setNewPassword.json @@ -15,6 +15,9 @@ "SUCCESS_MESSAGE": "Successfully changed the password", "ERROR_MESSAGE": "Could not connect to Woot Server, Please try again later" }, + "CAPTCHA": { + "ERROR": "Verification expired. Please solve captcha again." + }, "SUBMIT": "Submit" } } diff --git a/app/javascript/dashboard/routes/auth/Signup.vue b/app/javascript/dashboard/routes/auth/Signup.vue index 36b63662d..4f5aab8bd 100644 --- a/app/javascript/dashboard/routes/auth/Signup.vue +++ b/app/javascript/dashboard/routes/auth/Signup.vue @@ -77,9 +77,17 @@ />
+ + {{ $t('SET_NEW_PASSWORD.CAPTCHA.ERROR') }} +
From c397fe1964a2e139d29dc1273f7673f2a7fd8980 Mon Sep 17 00:00:00 2001 From: Pranav Raj S Date: Thu, 31 Mar 2022 21:21:25 +0530 Subject: [PATCH 06/20] fix: Update the URL for POST inbox_members (#4354) --- swagger/paths/index.yml | 10 ++- swagger/swagger.json | 133 +++++++++++++++++++++------------------- 2 files changed, 77 insertions(+), 66 deletions(-) diff --git a/swagger/paths/index.yml b/swagger/paths/index.yml index eeb2539f1..279ebb7bc 100644 --- a/swagger/paths/index.yml +++ b/swagger/paths/index.yml @@ -253,13 +253,17 @@ - $ref: '#/parameters/inbox_id' get: $ref: ./application/inboxes/inbox_members/show.yml - post: - $ref: ./application/inboxes/inbox_members/create.yml patch: $ref: ./application/inboxes/inbox_members/update.yml delete: $ref: ./application/inboxes/inbox_members/delete.yml +/api/v1/accounts/{account_id}/inbox_members: + parameters: + - $ref: '#/parameters/account_id' + post: + $ref: ./application/inboxes/inbox_members/create.yml + # Messages @@ -422,4 +426,4 @@ type: string description: The numeric ID of the user get: - $ref: './application/reports/conversation/agent.yml' \ No newline at end of file + $ref: './application/reports/conversation/agent.yml' diff --git a/swagger/swagger.json b/swagger/swagger.json index b17f9c586..4de4db49d 100644 --- a/swagger/swagger.json +++ b/swagger/swagger.json @@ -2803,69 +2803,6 @@ } } }, - "post": { - "tags": [ - "Inbox" - ], - "operationId": "add-new-agent-to-inbox", - "summary": "Add a New Agent", - "description": "Add a new Agent to Inbox", - "security": [ - { - "userApiKey": [ - - ] - } - ], - "parameters": [ - { - "name": "data", - "in": "body", - "required": true, - "schema": { - "type": "object", - "required": [ - "inbox_id", - "user_ids" - ], - "properties": { - "inbox_id": { - "type": "string", - "description": "The ID of the inbox" - }, - "user_ids": { - "type": "array", - "items": { - "type": "integer" - }, - "description": "IDs of users to be added to the inbox" - } - } - } - } - ], - "responses": { - "200": { - "description": "Success", - "schema": { - "type": "array", - "description": "Array of all active agents", - "items": { - "$ref": "#/definitions/agent" - } - } - }, - "404": { - "description": "Inbox not found" - }, - "403": { - "description": "Access denied" - }, - "422": { - "description": "User must exist" - } - } - }, "patch": { "tags": [ "Inbox" @@ -2986,6 +2923,76 @@ } } }, + "/api/v1/accounts/{account_id}/inbox_members": { + "parameters": [ + { + "$ref": "#/parameters/account_id" + } + ], + "post": { + "tags": [ + "Inbox" + ], + "operationId": "add-new-agent-to-inbox", + "summary": "Add a New Agent", + "description": "Add a new Agent to Inbox", + "security": [ + { + "userApiKey": [ + + ] + } + ], + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "inbox_id", + "user_ids" + ], + "properties": { + "inbox_id": { + "type": "string", + "description": "The ID of the inbox" + }, + "user_ids": { + "type": "array", + "items": { + "type": "integer" + }, + "description": "IDs of users to be added to the inbox" + } + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "array", + "description": "Array of all active agents", + "items": { + "$ref": "#/definitions/agent" + } + } + }, + "404": { + "description": "Inbox not found" + }, + "403": { + "description": "Access denied" + }, + "422": { + "description": "User must exist" + } + } + } + }, "/api/v1/accounts/{account_id}/conversations/{conversation_id}/messages": { "parameters": [ { From 3813b3b372d5dfd9e6a5b6c5ad403295ed322ad7 Mon Sep 17 00:00:00 2001 From: Vishnu Narayanan Date: Fri, 1 Apr 2022 00:34:50 +0530 Subject: [PATCH 07/20] feat: make linux script installation non-interactive (#4355) This PR changes the LetsEncrypt behaviour to be non-interactive. Earlier, the installation flow was waiting for user input at the SSL cert generation stage. With this change, once the user confirms completes the initial selection, the installation can be completed unattended. --- deployment/setup_20.04.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/deployment/setup_20.04.sh b/deployment/setup_20.04.sh index ca8b0a06a..14a0b74f6 100644 --- a/deployment/setup_20.04.sh +++ b/deployment/setup_20.04.sh @@ -2,7 +2,7 @@ # Description: Chatwoot installation script # OS: Ubuntu 20.04 LTS / Ubuntu 20.10 -# Script Version: 0.7 +# Script Version: 0.8 # Run this script as root read -p 'Would you like to configure a domain and SSL for Chatwoot?(yes or no): ' configure_webserver @@ -12,6 +12,7 @@ then read -p 'Enter your sub-domain to be used for Chatwoot (chatwoot.domain.com for example) : ' domain_name echo -e "\nThis script will try to generate SSL certificates via LetsEncrypt and serve chatwoot at "https://$domain_name". Proceed further once you have pointed your DNS to the IP of the instance.\n" +read -p 'Enter the email LetsEncrypt can use to send reminders when your SSL certificate is up for renewal: ' le_email read -p 'Do you wish to proceed? (yes or no): ' exit_true if [ $exit_true == "no" ] then @@ -138,7 +139,7 @@ else curl https://ssl-config.mozilla.org/ffdhe4096.txt >> /etc/ssl/dhparam wget https://raw.githubusercontent.com/chatwoot/chatwoot/develop/deployment/nginx_chatwoot.conf cp nginx_chatwoot.conf /etc/nginx/sites-available/nginx_chatwoot.conf -certbot certonly --nginx -d $domain_name +certbot certonly --non-interactive --agree-tos --nginx -m $le_email -d $domain_name sed -i "s/chatwoot.domain.com/$domain_name/g" /etc/nginx/sites-available/nginx_chatwoot.conf ln -s /etc/nginx/sites-available/nginx_chatwoot.conf /etc/nginx/sites-enabled/nginx_chatwoot.conf systemctl restart nginx From caee9535f1f99168a19a88187c170e0b695179b6 Mon Sep 17 00:00:00 2001 From: Sivin Varghese <64252451+iamsivin@users.noreply.github.com> Date: Fri, 1 Apr 2022 20:59:03 +0530 Subject: [PATCH 08/20] feat: Support Dark mode for the widget (#4137) Co-authored-by: Pranav Raj S --- app/controllers/widget_tests_controller.rb | 5 ++ .../dashboard/settings/agents/Index.vue | 4 +- app/javascript/packs/sdk.js | 9 +++- app/javascript/sdk/IFrameHelper.js | 1 + app/javascript/sdk/constants.js | 1 + app/javascript/sdk/settingsHelper.js | 5 +- app/javascript/shared/components/ChatCard.vue | 17 +++--- app/javascript/shared/components/ChatForm.vue | 21 ++++++-- .../shared/components/ChatOption.vue | 2 +- .../shared/components/ChatOptions.vue | 10 ++-- .../components/CustomerSatisfaction.vue | 28 +++++++--- .../shared/components/DateSeparator.vue | 9 +++- .../shared/components/ResizableTextArea.vue | 1 - .../components/specs/DateSeparator.spec.js | 53 +++++++++++++++---- .../__snapshots__/DateSeparator.spec.js.snap | 4 +- .../assets/scss/views/_conversation.scss | 3 -- .../widget/components/AgentMessage.vue | 12 +++-- .../widget/components/AgentMessageBubble.vue | 10 +++- .../widget/components/AgentTypingBubble.vue | 7 ++- .../widget/components/ChatHeader.vue | 28 +++++++--- .../widget/components/ChatHeaderExpanded.vue | 17 ++++-- .../widget/components/ChatInputWrap.vue | 25 ++++++--- .../widget/components/Form/Input.vue | 39 +++++++++----- .../widget/components/Form/TextArea.vue | 37 ++++++++----- .../widget/components/HeaderActions.vue | 20 +++++-- .../widget/components/PreChat/Form.vue | 6 ++- .../widget/components/TeamAvailability.vue | 12 +++-- .../widget/components/UnreadMessage.vue | 9 +++- .../components/layouts/ViewWithHeader.vue | 13 +++-- .../widget/components/template/Article.vue | 24 +++++++-- .../widget/components/template/EmailInput.vue | 17 +++++- app/javascript/widget/mixins/darkModeMixin.js | 15 ++++++ .../widget/mixins/specs/darkModeMixin.spec.js | 41 ++++++++++++++ .../widget/store/modules/appConfig.js | 12 ++++- app/views/widget_tests/index.html.erb | 1 + tailwind.config.js | 6 ++- 36 files changed, 411 insertions(+), 113 deletions(-) create mode 100644 app/javascript/widget/mixins/darkModeMixin.js create mode 100644 app/javascript/widget/mixins/specs/darkModeMixin.spec.js diff --git a/app/controllers/widget_tests_controller.rb b/app/controllers/widget_tests_controller.rb index fff47d907..6d6742cf4 100644 --- a/app/controllers/widget_tests_controller.rb +++ b/app/controllers/widget_tests_controller.rb @@ -3,6 +3,7 @@ class WidgetTestsController < ActionController::Base before_action :ensure_widget_position before_action :ensure_widget_type before_action :ensure_widget_style + before_action :ensure_dark_mode def index render @@ -14,6 +15,10 @@ class WidgetTestsController < ActionController::Base @widget_style = params[:widget_style] || 'standard' end + def ensure_dark_mode + @dark_mode = params[:dark_mode] || 'light' + end + def ensure_widget_position @widget_position = params[:position] || 'left' end diff --git a/app/javascript/dashboard/routes/dashboard/settings/agents/Index.vue b/app/javascript/dashboard/routes/dashboard/settings/agents/Index.vue index c3a75b0f6..5714582d5 100644 --- a/app/javascript/dashboard/routes/dashboard/settings/agents/Index.vue +++ b/app/javascript/dashboard/routes/dashboard/settings/agents/Index.vue @@ -35,7 +35,9 @@ - {{ agent.name }} + + {{ agent.name }} + {{ agent.email }} diff --git a/app/javascript/packs/sdk.js b/app/javascript/packs/sdk.js index 76e1a2cd8..b77b682dd 100755 --- a/app/javascript/packs/sdk.js +++ b/app/javascript/packs/sdk.js @@ -1,6 +1,10 @@ import Cookies from 'js-cookie'; import { IFrameHelper } from '../sdk/IFrameHelper'; -import { getBubbleView } from '../sdk/settingsHelper'; +import { + getBubbleView, + getDarkMode, + getWidgetStyle, +} from '../sdk/settingsHelper'; import { computeHashForUserData, getUserCookieName, @@ -24,8 +28,9 @@ const runSDK = ({ baseUrl, websiteToken }) => { type: getBubbleView(chatwootSettings.type), launcherTitle: chatwootSettings.launcherTitle || '', showPopoutButton: chatwootSettings.showPopoutButton || false, - widgetStyle: chatwootSettings.widgetStyle || 'standard', + widgetStyle: getWidgetStyle(chatwootSettings.widgetStyle) || 'standard', resetTriggered: false, + darkMode: getDarkMode(chatwootSettings.darkMode), toggle(state) { IFrameHelper.events.toggleBubble(state); diff --git a/app/javascript/sdk/IFrameHelper.js b/app/javascript/sdk/IFrameHelper.js index df36d8e0d..3bc0973fe 100644 --- a/app/javascript/sdk/IFrameHelper.js +++ b/app/javascript/sdk/IFrameHelper.js @@ -145,6 +145,7 @@ export const IFrameHelper = { hideMessageBubble: window.$chatwoot.hideMessageBubble, showPopoutButton: window.$chatwoot.showPopoutButton, widgetStyle: window.$chatwoot.widgetStyle, + darkMode: window.$chatwoot.darkMode, }); IFrameHelper.onLoad({ widgetColor: message.config.channelConfig.widgetColor, diff --git a/app/javascript/sdk/constants.js b/app/javascript/sdk/constants.js index 52faf1540..7bf84d430 100644 --- a/app/javascript/sdk/constants.js +++ b/app/javascript/sdk/constants.js @@ -1,2 +1,3 @@ export const BUBBLE_DESIGN = ['standard', 'expanded_bubble']; export const WIDGET_DESIGN = ['standard', 'flat']; +export const DARK_MODE = ['light', 'auto']; diff --git a/app/javascript/sdk/settingsHelper.js b/app/javascript/sdk/settingsHelper.js index 4e256b53a..657db1fe0 100644 --- a/app/javascript/sdk/settingsHelper.js +++ b/app/javascript/sdk/settingsHelper.js @@ -1,4 +1,4 @@ -import { BUBBLE_DESIGN, WIDGET_DESIGN } from './constants'; +import { BUBBLE_DESIGN, DARK_MODE, WIDGET_DESIGN } from './constants'; export const getBubbleView = type => BUBBLE_DESIGN.includes(type) ? type : BUBBLE_DESIGN[0]; @@ -9,3 +9,6 @@ export const getWidgetStyle = style => WIDGET_DESIGN.includes(style) ? style : WIDGET_DESIGN[0]; export const isFlatWidgetStyle = style => style === 'flat'; + +export const getDarkMode = darkMode => + DARK_MODE.includes(darkMode) ? darkMode : DARK_MODE[0]; diff --git a/app/javascript/shared/components/ChatCard.vue b/app/javascript/shared/components/ChatCard.vue index 4e856bb6b..eb6e13364 100644 --- a/app/javascript/shared/components/ChatCard.vue +++ b/app/javascript/shared/components/ChatCard.vue @@ -1,11 +1,14 @@