diff --git a/app/controllers/api/v1/accounts/integrations/slack_controller.rb b/app/controllers/api/v1/accounts/integrations/slack_controller.rb index b5571b245..eaa18c2de 100644 --- a/app/controllers/api/v1/accounts/integrations/slack_controller.rb +++ b/app/controllers/api/v1/accounts/integrations/slack_controller.rb @@ -1,27 +1,27 @@ class Api::V1::Accounts::Integrations::SlackController < Api::V1::Accounts::BaseController before_action :check_admin_authorization? - before_action :fetch_hook, only: [:update, :destroy] + before_action :fetch_hook, only: [:update, :destroy, :list_all_channels] + + def list_all_channels + @channels = channel_builder.fetch_channels + end def create - ActiveRecord::Base.transaction do - builder = Integrations::Slack::HookBuilder.new( - account: Current.account, - code: params[:code], - inbox_id: params[:inbox_id] - ) - @hook = builder.perform - create_chatwoot_slack_channel - end + hook_builder = Integrations::Slack::HookBuilder.new( + account: Current.account, + code: params[:code], + inbox_id: params[:inbox_id] + ) + @hook = hook_builder.perform end def update - create_chatwoot_slack_channel - render json: @hook + @hook = channel_builder.update(permitted_params[:reference_id]) + render json: { error: I18n.t('errors.slack.invalid_channel_id') }, status: :unprocessable_entity if @hook.blank? end def destroy @hook.destroy! - head :ok end @@ -31,11 +31,11 @@ class Api::V1::Accounts::Integrations::SlackController < Api::V1::Accounts::Base @hook = Integrations::Hook.where(account: Current.account).find_by(app_id: 'slack') end - def create_chatwoot_slack_channel - channel = params[:channel] || 'customer-conversations' - builder = Integrations::Slack::ChannelBuilder.new( - hook: @hook, channel: channel - ) - builder.perform + def channel_builder + Integrations::Slack::ChannelBuilder.new(hook: @hook) + end + + def permitted_params + params.permit(:reference_id) end end diff --git a/app/javascript/dashboard/api/integrations.js b/app/javascript/dashboard/api/integrations.js index 72e433c25..2b816e603 100644 --- a/app/javascript/dashboard/api/integrations.js +++ b/app/javascript/dashboard/api/integrations.js @@ -8,11 +8,19 @@ class IntegrationsAPI extends ApiClient { } connectSlack(code) { - return axios.post(`${this.baseUrl()}/integrations/slack`, { - code: code, + return axios.post(`${this.baseUrl()}/integrations/slack`, { code }); + } + + updateSlack({ referenceId }) { + return axios.patch(`${this.baseUrl()}/integrations/slack`, { + reference_id: referenceId, }); } + listAllSlackChannels() { + return axios.get(`${this.baseUrl()}/integrations/slack/list_all_channels`); + } + delete(integrationId) { return axios.delete(`${this.baseUrl()}/integrations/${integrationId}`); } diff --git a/app/javascript/dashboard/api/specs/integrations.spec.js b/app/javascript/dashboard/api/specs/integrations.spec.js index 05391ceb6..890cc7c84 100644 --- a/app/javascript/dashboard/api/specs/integrations.spec.js +++ b/app/javascript/dashboard/api/specs/integrations.spec.js @@ -11,7 +11,9 @@ describe('#integrationAPI', () => { expect(integrationAPI).toHaveProperty('update'); expect(integrationAPI).toHaveProperty('delete'); expect(integrationAPI).toHaveProperty('connectSlack'); - expect(integrationAPI).toHaveProperty('createHook'); + expect(integrationAPI).toHaveProperty('updateSlack'); + expect(integrationAPI).toHaveProperty('updateSlack'); + expect(integrationAPI).toHaveProperty('listAllSlackChannels'); expect(integrationAPI).toHaveProperty('deleteHook'); }); describeWithAPIMock('API calls', context => { @@ -26,6 +28,24 @@ describe('#integrationAPI', () => { ); }); + it('#updateSlack', () => { + const updateObj = { referenceId: 'SDFSDGSVE' }; + integrationAPI.updateSlack(updateObj); + expect(context.axiosMock.patch).toHaveBeenCalledWith( + '/api/v1/integrations/slack', + { + reference_id: updateObj.referenceId, + } + ); + }); + + it('#listAllSlackChannels', () => { + integrationAPI.listAllSlackChannels(); + expect(context.axiosMock.get).toHaveBeenCalledWith( + '/api/v1/integrations/slack/list_all_channels' + ); + }); + it('#delete', () => { integrationAPI.delete(2); expect(context.axiosMock.delete).toHaveBeenCalledWith( diff --git a/app/javascript/dashboard/components/ChatList.vue b/app/javascript/dashboard/components/ChatList.vue index 32cbe9f72..ce58aca09 100644 --- a/app/javascript/dashboard/components/ChatList.vue +++ b/app/javascript/dashboard/components/ChatList.vue @@ -1,6 +1,6 @@ @@ -40,6 +40,10 @@ export default { type: String, default: '', }, + spinnerClass: { + type: String, + default: '', + }, type: { type: String, default: 'submit', diff --git a/app/javascript/dashboard/components/layout/config/sidebarItems/settings.js b/app/javascript/dashboard/components/layout/config/sidebarItems/settings.js index c0d80932d..6cc4e69b7 100644 --- a/app/javascript/dashboard/components/layout/config/sidebarItems/settings.js +++ b/app/javascript/dashboard/components/layout/config/sidebarItems/settings.js @@ -29,6 +29,7 @@ const settings = accountId => ({ 'settings_inboxes_page_channel', 'settings_integrations_dashboard_apps', 'settings_integrations_integration', + 'settings_integrations_slack', 'settings_integrations_webhook', 'settings_integrations', 'settings_teams_add_agents', diff --git a/app/javascript/dashboard/i18n/locale/en/integrations.json b/app/javascript/dashboard/i18n/locale/en/integrations.json index f2cbeea24..2ebc4fd69 100644 --- a/app/javascript/dashboard/i18n/locale/en/integrations.json +++ b/app/javascript/dashboard/i18n/locale/en/integrations.json @@ -70,10 +70,26 @@ } }, "SLACK": { + "DELETE": "Delete", + "DELETE_CONFIRMATION": { + "TITLE": "Delete the integration", + "MESSAGE": "Are you sure you want to delete the integration? Doing so will result in the loss of access to conversations on your Slack workspace." + }, "HELP_TEXT": { - "TITLE": "Using Slack Integration", - "BODY": "

Chatwoot will now sync all the incoming conversations into the customer-conversations channel inside your slack workplace.

Replying to a conversation thread in customer-conversations slack channel will create a response back to the customer through chatwoot.

Start the replies with note: to create private notes instead of replies.

If the replier on slack has an agent profile in chatwoot under the same email, the replies will be associated accordingly.

When the replier doesn't have an associated agent profile, the replies will be made from the bot profile.

" - } + "TITLE": "How to use the Slack Integration?", + "BODY": "With this integration, all of your incoming conversations will be synced to the ***%{selectedChannelName}*** channel in your Slack workspace. You can manage all your customer conversations right within the channel and never miss a message.\n\nHere are the main features of the integration:\n\n**Respond to conversations from within Slack:** To respond to a conversation in the ***%{selectedChannelName}*** Slack channel, simply type out your message and send it as a thread. This will create a response back to the customer through Chatwoot. It's that simple!\n\n **Create private notes:** If you want to create private notes instead of replies, start your message with ***`note:`***. This ensures that your message is kept private and won't be visible to the customer.\n\n**Associate an agent profile:** If the person who replied on Slack has an agent profile in Chatwoot under the same email, the replies will be associated with that agent profile automatically. This means you can easily track who said what and when. On the other hand, when the replier doesn't have an associated agent profile, the replies will appear from the bot profile to the customer.", + "SELECTED": "selected" + }, + "SELECT_CHANNEL": { + "OPTION_LABEL": "Select a channel", + "UPDATE": "Update", + "BUTTON_TEXT": "Connect channel", + "DESCRIPTION": "Your Slack workspace is now linked with Chatwoot. However, the integration is currently inactive. To activate the integration and connect a channel to Chatwoot, please click the button below.\n\n**Note:** If you are attempting to connect a private channel, add the Chatwoot app to the Slack channel before proceeding with this step.", + "ATTENTION_REQUIRED": "Attention required" + }, + "UPDATE_ERROR": "There was an error updating the integration, please try again", + "UPDATE_SUCCESS": "The channel is connected successfully", + "FAILED_TO_FETCH_CHANNELS": "There was an error fetching the channels from Slack, please try again" }, "DYTE": { "CLICK_HERE_TO_JOIN": "Click here to join", diff --git a/app/javascript/dashboard/routes/dashboard/settings/integrations/Integration.vue b/app/javascript/dashboard/routes/dashboard/settings/integrations/Integration.vue index 688c19904..7e60af5eb 100644 --- a/app/javascript/dashboard/routes/dashboard/settings/integrations/Integration.vue +++ b/app/javascript/dashboard/routes/dashboard/settings/integrations/Integration.vue @@ -1,23 +1,23 @@