diff --git a/.env.example b/.env.example index 7c5299bad..624a44a7b 100644 --- a/.env.example +++ b/.env.example @@ -39,17 +39,24 @@ POSTGRES_PASSWORD= RAILS_ENV=development RAILS_MAX_THREADS=5 -# Mail outgoing -MAILER_SENDER_EMAIL=accounts@chatwoot.com -SMTP_PORT=1025 +# The email from which all outgoing emails are sent +# could user either `email@yourdomain.com` or `BrandName ` +MAILER_SENDER_EMAIL=Chatwoot + + +#SMTP domain key is set up for HELO checking SMTP_DOMAIN=chatwoot.com -# if you are running docker-compose, set SMTP_ADDRESS value as "mailhog", -# else set the value as "localhost" +# the default value is set "mailhog" and is used by docker-compose for development environments, +# Set the value as "localhost" or your SMTP address in other environments SMTP_ADDRESS=mailhog +SMTP_PORT=1025 SMTP_USERNAME= SMTP_PASSWORD= +# plain,login,cram_md5 SMTP_AUTHENTICATION= -SMTP_ENABLE_STARTTLS_AUTO= +SMTP_ENABLE_STARTTLS_AUTO=true +# Can be: 'none', 'peer', 'client_once', 'fail_if_no_peer_cert', see http://api.rubyonrails.org/classes/ActionMailer/Base.html +SMTP_OPENSSL_VERIFY_MODE=peer # Mail Incoming # This is the domain set for the reply emails when conversation continuity is enabled diff --git a/Gemfile.lock b/Gemfile.lock index 5dbad5245..f235fe683 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -133,7 +133,7 @@ GEM bootsnap (1.4.8) msgpack (~> 1.0) brakeman (4.9.0) - browser (4.2.0) + browser (5.3.1) builder (3.2.4) bullet (6.1.0) activesupport (>= 3.0.0) diff --git a/app/controllers/api/v1/accounts/inboxes_controller.rb b/app/controllers/api/v1/accounts/inboxes_controller.rb index 6c078d28f..7928a3d41 100644 --- a/app/controllers/api/v1/accounts/inboxes_controller.rb +++ b/app/controllers/api/v1/accounts/inboxes_controller.rb @@ -23,6 +23,7 @@ class Api::V1::Accounts::InboxesController < Api::V1::Accounts::BaseController def update @inbox.update(inbox_update_params.except(:channel)) + @inbox.update_working_hours(params.permit(working_hours: Inbox::OFFISABLE_ATTRS)[:working_hours]) if params[:working_hours] return unless @inbox.channel.is_a?(Channel::WebWidget) && inbox_update_params[:channel].present? @inbox.channel.update!(inbox_update_params[:channel]) @@ -80,7 +81,7 @@ class Api::V1::Accounts::InboxesController < Api::V1::Accounts::BaseController def inbox_update_params params.permit(:enable_auto_assignment, :name, :avatar, :greeting_message, :greeting_enabled, - :working_hours_enabled, :out_of_office_message, + :working_hours_enabled, :out_of_office_message, :timezone, channel: [ :website_url, :widget_color, diff --git a/app/controllers/platform/api/v1/users_controller.rb b/app/controllers/platform/api/v1/users_controller.rb index 81b526c8e..b6e9237b9 100644 --- a/app/controllers/platform/api/v1/users_controller.rb +++ b/app/controllers/platform/api/v1/users_controller.rb @@ -10,20 +10,16 @@ class Platform::Api::V1::UsersController < PlatformController @resource.confirm @resource.save! @platform_app.platform_app_permissibles.find_or_create_by(permissible: @resource) - render json: @resource end def login render json: { url: "#{ENV['FRONTEND_URL']}/app/login?email=#{@resource.email}&sso_auth_token=#{@resource.generate_sso_auth_token}" } end - def show - render json: @resource - end + def show; end def update @resource.update!(user_params) - render json: @resource end def destroy diff --git a/app/controllers/widgets_controller.rb b/app/controllers/widgets_controller.rb index da634875a..44a23568e 100644 --- a/app/controllers/widgets_controller.rb +++ b/app/controllers/widgets_controller.rb @@ -6,8 +6,6 @@ class WidgetsController < ActionController::Base before_action :build_contact after_action :allow_iframe_requests - def index; end - private def set_global_config diff --git a/app/javascript/dashboard/api/inbox/conversation.js b/app/javascript/dashboard/api/inbox/conversation.js index 159e77f0e..b520156a4 100644 --- a/app/javascript/dashboard/api/inbox/conversation.js +++ b/app/javascript/dashboard/api/inbox/conversation.js @@ -33,12 +33,17 @@ class ConversationApi extends ApiClient { } assignAgent({ conversationId, agentId }) { - axios.post( + return axios.post( `${this.url}/${conversationId}/assignments?assignee_id=${agentId}`, {} ); } + assignTeam({ conversationId, teamId }) { + const params = { team_id: teamId }; + return axios.post(`${this.url}/${conversationId}/assignments`, params); + } + markMessageRead({ id }) { return axios.post(`${this.url}/${id}/update_last_seen`); } diff --git a/app/javascript/dashboard/api/specs/inbox/conversation.spec.js b/app/javascript/dashboard/api/specs/inbox/conversation.spec.js index 31be5e87e..6d4cdeec4 100644 --- a/app/javascript/dashboard/api/specs/inbox/conversation.spec.js +++ b/app/javascript/dashboard/api/specs/inbox/conversation.spec.js @@ -11,6 +11,7 @@ describe('#ConversationAPI', () => { expect(conversationAPI).toHaveProperty('delete'); expect(conversationAPI).toHaveProperty('toggleStatus'); expect(conversationAPI).toHaveProperty('assignAgent'); + expect(conversationAPI).toHaveProperty('assignTeam'); expect(conversationAPI).toHaveProperty('markMessageRead'); expect(conversationAPI).toHaveProperty('toggleTyping'); expect(conversationAPI).toHaveProperty('mute'); diff --git a/app/javascript/dashboard/api/specs/teams.spec.js b/app/javascript/dashboard/api/specs/teams.spec.js index 7622a5417..6b01ab359 100644 --- a/app/javascript/dashboard/api/specs/teams.spec.js +++ b/app/javascript/dashboard/api/specs/teams.spec.js @@ -11,5 +11,6 @@ describe('#TeamsAPI', () => { expect(teams).toHaveProperty('delete'); expect(teams).toHaveProperty('getAgents'); expect(teams).toHaveProperty('addAgents'); + expect(teams).toHaveProperty('updateAgents'); }); }); diff --git a/app/javascript/dashboard/api/teams.js b/app/javascript/dashboard/api/teams.js index 9c117c71b..ba202dff2 100644 --- a/app/javascript/dashboard/api/teams.js +++ b/app/javascript/dashboard/api/teams.js @@ -15,6 +15,12 @@ export class TeamsAPI extends ApiClient { user_ids: agentsList, }); } + + updateAgents({ teamId, agentsList }) { + return axios.patch(`${this.url}/${teamId}/team_members`, { + user_ids: agentsList, + }); + } } export default new TeamsAPI(); diff --git a/app/javascript/dashboard/assets/scss/_foundation-custom.scss b/app/javascript/dashboard/assets/scss/_foundation-custom.scss index d76fef07d..d93c60aa4 100644 --- a/app/javascript/dashboard/assets/scss/_foundation-custom.scss +++ b/app/javascript/dashboard/assets/scss/_foundation-custom.scss @@ -44,3 +44,7 @@ code { text-overflow: ellipsis; white-space: nowrap; } + +.cursor-pointer { + cursor: pointer; +} diff --git a/app/javascript/dashboard/assets/scss/_foundation-settings.scss b/app/javascript/dashboard/assets/scss/_foundation-settings.scss index 79bc1ae29..e8862b5bf 100644 --- a/app/javascript/dashboard/assets/scss/_foundation-settings.scss +++ b/app/javascript/dashboard/assets/scss/_foundation-settings.scss @@ -89,7 +89,9 @@ $breakpoints: (small: 0, medium: 640px, large: 1024px, xlarge: 1200px, - xxlarge: 1440px); + xxlarge: 1400px, + xxxlarge: 1600px, +); $print-breakpoint: large; $breakpoint-classes: (small medium large); diff --git a/app/javascript/dashboard/assets/scss/plugins/_multiselect.scss b/app/javascript/dashboard/assets/scss/plugins/_multiselect.scss index 480e31c61..36df6af14 100644 --- a/app/javascript/dashboard/assets/scss/plugins/_multiselect.scss +++ b/app/javascript/dashboard/assets/scss/plugins/_multiselect.scss @@ -13,17 +13,16 @@ } .multiselect { - margin-bottom: $space-normal; - min-height: 38px; + margin-bottom: var(--space-normal); - &.multiselect--active { + .multiselect--active { >.multiselect__tags { border-color: $color-woot; } } .multiselect__select { - min-height: 44px; + min-height: 4.6rem; padding: 0; right: 0; top: 0; @@ -39,16 +38,51 @@ font-weight: $font-weight-normal; &.multiselect__option--highlight { - font-weight: $font-weight-medium; + background: var(--white); + color: var(--color-body); + } + + &.multiselect__option--highlight:hover { + background: var(--w-50); + color: var(--color-body); + + &::after { + background: var(--w-50); + color: var(--s-600); + } + } + + &.multiselect__option--highlight::after { + background: transparent; + } + + &.multiselect__option--selected { + background: var(--w-400); + color: var(--white); + + &.multiselect__option--highlight:hover { + background: var(--w-600); + color: var(--white); + + &::after { + background: transparent; + color: var(--white); + + &:hover { + color: var(--color-body); + } + } + } } } -} -.multiselect>.multiselect__tags { - @include margin(0); - border: 1px solid $color-border; - min-height: 44px; - padding-top: $zero; + .multiselect__tags { + @include margin(0); + border: 1px solid $color-border; + border-color: $color-border; + min-height: 4.4rem; + padding-top: $zero; + } .multiselect__tags-wrap { display: inline-block; @@ -59,7 +93,7 @@ .multiselect__placeholder { color: $color-gray; font-weight: $font-weight-normal; - padding-top: $space-small; + padding-top: var(--space-slab); } .multiselect__tag { @@ -79,31 +113,23 @@ @include ghost-input; @include padding($zero); font-size: $font-size-small; - + height: 4.4rem; margin-bottom: $zero; } .multiselect__single { - @include padding($space-one); - margin-bottom: 0; + padding: var(--space-slab) var(--space-one); } } .sidebar-labels-wrap { + &.has-edited, &:hover { .multiselect { cursor: pointer; } - - .multiselect>.multiselect__tags { - border-color: $color-border; - } - - .multiselect>.multiselect__select { - visibility: visible; - } } .multiselect { @@ -120,3 +146,35 @@ } } } + + +.multiselect-wrap--small { + $multiselect-height: 3.8rem; + + .multiselect__tags, + .multiselect__input, + .multiselect { + background: var(--white); + font-size: var(--font-size-small); + height: $multiselect-height; + min-height: $multiselect-height; + } + + .multiselect__input { + height: $multiselect-height - $space-micro; + min-height: $multiselect-height - $space-micro; + } + + .multiselect__single { + font-size: var(--font-size-small); + padding: var(--space-small) 0; + } + + .multiselect__placeholder { + padding: var(--space-small) 0; + } + + .multiselect__select { + min-height: $multiselect-height; + } +} diff --git a/app/javascript/dashboard/assets/scss/widgets/_buttons.scss b/app/javascript/dashboard/assets/scss/widgets/_buttons.scss index 07089b399..a599721c2 100644 --- a/app/javascript/dashboard/assets/scss/widgets/_buttons.scss +++ b/app/javascript/dashboard/assets/scss/widgets/_buttons.scss @@ -2,12 +2,17 @@ margin-bottom: 0; &.button--emoji { + align-items: center; background: var(--b-50); border: 1px solid var(--color-border-light); border-radius: var(--border-radius-large); + display: flex; font-size: var(--font-size-small); - margin-right: var(--space-small); - padding: var(--space-small); + height: var(--space-large); + justify-content: center; + padding: var(--space-micro); + text-align: center; + width: var(--space-large); &:hover { background: var(--b-200); diff --git a/app/javascript/dashboard/assets/scss/widgets/_conv-header.scss b/app/javascript/dashboard/assets/scss/widgets/_conv-header.scss index c6cc66c96..69363e542 100644 --- a/app/javascript/dashboard/assets/scss/widgets/_conv-header.scss +++ b/app/javascript/dashboard/assets/scss/widgets/_conv-header.scss @@ -43,10 +43,6 @@ $resolve-button-width: 13.2rem; @include flex; @include flex-align($x: center, $y: middle); - &.hide { - visibility: hidden; - } - .user--name { @include margin(0); font-size: $font-size-medium; diff --git a/app/javascript/dashboard/assets/scss/widgets/_conversation-card.scss b/app/javascript/dashboard/assets/scss/widgets/_conversation-card.scss index 06749c99d..11394f032 100644 --- a/app/javascript/dashboard/assets/scss/widgets/_conversation-card.scss +++ b/app/javascript/dashboard/assets/scss/widgets/_conversation-card.scss @@ -14,7 +14,6 @@ @include flex; @include flex-shrink; @include padding(0 0 0 $space-normal); - align-items: center; border-bottom: 1px solid transparent; border-left: $space-micro solid transparent; border-top: 1px solid transparent; diff --git a/app/javascript/dashboard/assets/scss/widgets/_conversation-view.scss b/app/javascript/dashboard/assets/scss/widgets/_conversation-view.scss index d518812f1..297166b66 100644 --- a/app/javascript/dashboard/assets/scss/widgets/_conversation-view.scss +++ b/app/javascript/dashboard/assets/scss/widgets/_conversation-view.scss @@ -42,7 +42,7 @@ } } -.conversations-sidebar { +.conversations-list-wrap { @include flex; flex-direction: column; @@ -92,44 +92,6 @@ } } -.conversation-wrap { - @include margin(0); - @include border-normal-left; - background: var(--color-background-light); - - .current-chat { - @include flex; - @include full-height; - @include flex-align(center, middle); - flex-direction: column; - - div { - @include flex; - @include full-height; - @include flex-align(center, middle); - flex-direction: column; - - img { - @include margin($space-normal); - width: 10rem; - } - - span { - font-size: $font-size-small; - font-weight: $font-weight-medium; - text-align: center; - } - } - } - - .conv-empty-state { - @include flex; - @include full-height; - @include flex-align(center, middle); - flex-direction: column; - } -} - .conversation-panel { @include flex; @include flex-weight(1); diff --git a/app/javascript/dashboard/assets/scss/widgets/_reply-box.scss b/app/javascript/dashboard/assets/scss/widgets/_reply-box.scss index d91e192d2..c09812527 100644 --- a/app/javascript/dashboard/assets/scss/widgets/_reply-box.scss +++ b/app/javascript/dashboard/assets/scss/widgets/_reply-box.scss @@ -61,9 +61,7 @@ } .bottom-box .button--emoji.button--upload { - height: var(--space-large); padding: 0; - width: var(--space-large); .file-uploads { height: 100%; diff --git a/app/javascript/dashboard/assets/scss/widgets/_sidemenu.scss b/app/javascript/dashboard/assets/scss/widgets/_sidemenu.scss index 344317735..65abd09c7 100644 --- a/app/javascript/dashboard/assets/scss/widgets/_sidemenu.scss +++ b/app/javascript/dashboard/assets/scss/widgets/_sidemenu.scss @@ -49,10 +49,8 @@ margin-top: $space-micro; .inbox-icon { - $icon-top-space: -1px; display: inline-block; margin-right: $space-micro; - margin-top: $icon-top-space; min-width: $space-normal; text-align: center; } diff --git a/app/javascript/dashboard/components/ChatList.vue b/app/javascript/dashboard/components/ChatList.vue index 8637c071a..6603a25c6 100644 --- a/app/javascript/dashboard/components/ChatList.vue +++ b/app/javascript/dashboard/components/ChatList.vue @@ -1,5 +1,5 @@