From 97d7b9d754ab80ae12ebbdf22978ee62c49e9199 Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Tue, 12 Nov 2024 07:09:09 +0530 Subject: [PATCH] feat(ee): Setup @chatwoot/captain NPM library (#10389) --- Co-authored-by: Sojan Co-authored-by: Pranav --- .../integrations/captain_controller.rb | 53 +- app/javascript/dashboard/api/integrations.js | 4 +- .../components-next/sidebar/Sidebar.vue | 20 +- .../components-next/sidebar/SidebarGroup.vue | 4 +- .../layout/config/sidebarItems/primaryMenu.js | 2 +- .../dashboard/routes/dashboard/Captain.vue | 152 +++-- .../routes/dashboard/dashboard.routes.js | 3 +- config/routes.rb | 2 +- package.json | 9 +- pnpm-lock.yaml | 618 ++++++++++++++---- .../integrations/captain_controller_spec.rb | 98 +-- tailwind.config.js | 7 + 12 files changed, 710 insertions(+), 262 deletions(-) diff --git a/app/controllers/api/v1/accounts/integrations/captain_controller.rb b/app/controllers/api/v1/accounts/integrations/captain_controller.rb index 7df0e61df..840fe5428 100644 --- a/app/controllers/api/v1/accounts/integrations/captain_controller.rb +++ b/app/controllers/api/v1/accounts/integrations/captain_controller.rb @@ -1,22 +1,47 @@ class Api::V1::Accounts::Integrations::CaptainController < Api::V1::Accounts::BaseController - before_action :check_admin_authorization? - before_action :fetch_hook + before_action :hook - def sso_url - params_string = - "token=#{URI.encode_www_form_component(@hook['settings']['access_token'])}" \ - "&email=#{URI.encode_www_form_component(@hook['settings']['account_email'])}" \ - "&account_id=#{URI.encode_www_form_component(@hook['settings']['account_id'])}" - - installation_config = InstallationConfig.find_by(name: 'CAPTAIN_APP_URL') - - sso_url = "#{installation_config.value}/sso?#{params_string}" - render json: { sso_url: sso_url }, status: :ok + def proxy + response = HTTParty.send(request_method, request_url, body: permitted_params[:body].to_json, headers: headers) + render plain: response.body, status: response.code end private - def fetch_hook - @hook = Current.account.hooks.find_by!(app_id: 'captain') + def headers + { + 'X-User-Email' => hook.settings['account_email'], + 'X-User-Token' => hook.settings['access_token'], + 'Content-Type' => 'application/json', + 'Accept' => '*/*' + } + end + + def request_path + if params[:route] == '/sessions/profile' + 'api/sessions/profile' + else + "api/accounts/#{hook.settings['account_id']}/#{params[:route]}" + end + end + + def request_url + base_url = InstallationConfig.find_by(name: 'CAPTAIN_API_URL').value + URI.join(base_url, request_path).to_s + end + + def hook + @hook ||= Current.account.hooks.find_by!(app_id: 'captain') + end + + def request_method + method = permitted_params[:method].downcase + raise 'Invalid or missing HTTP method' unless %w[get post put patch delete options head].include?(method) + + method + end + + def permitted_params + params.permit(:method, :route, body: {}) end end diff --git a/app/javascript/dashboard/api/integrations.js b/app/javascript/dashboard/api/integrations.js index 975857ce1..59a3e244a 100644 --- a/app/javascript/dashboard/api/integrations.js +++ b/app/javascript/dashboard/api/integrations.js @@ -33,8 +33,8 @@ class IntegrationsAPI extends ApiClient { return axios.delete(`${this.baseUrl()}/integrations/hooks/${hookId}`); } - fetchCaptainURL() { - return axios.get(`${this.baseUrl()}/integrations/captain/sso_url`); + requestCaptain(body) { + return axios.post(`${this.baseUrl()}/integrations/captain/proxy`, body); } } diff --git a/app/javascript/dashboard/components-next/sidebar/Sidebar.vue b/app/javascript/dashboard/components-next/sidebar/Sidebar.vue index 0d4421f89..a7d3a1cee 100644 --- a/app/javascript/dashboard/components-next/sidebar/Sidebar.vue +++ b/app/javascript/dashboard/components-next/sidebar/Sidebar.vue @@ -164,9 +164,25 @@ const menuItems = computed(() => { }, { name: 'Captain', - icon: 'i-lucide-bot', + icon: 'i-woot-captain', label: t('SIDEBAR.CAPTAIN'), - to: accountScopedRoute('captain'), + children: [ + { + name: 'Documents', + label: 'Documents', + to: accountScopedRoute('captain', { page: 'documents' }), + }, + { + name: 'Responses', + label: 'Responses', + to: accountScopedRoute('captain', { page: 'responses' }), + }, + { + name: 'Playground', + label: 'Playground', + to: accountScopedRoute('captain', { page: 'playground' }), + }, + ], }, { name: 'Contacts', diff --git a/app/javascript/dashboard/components-next/sidebar/SidebarGroup.vue b/app/javascript/dashboard/components-next/sidebar/SidebarGroup.vue index 89d99d402..f7bc2362d 100644 --- a/app/javascript/dashboard/components-next/sidebar/SidebarGroup.vue +++ b/app/javascript/dashboard/components-next/sidebar/SidebarGroup.vue @@ -122,7 +122,9 @@ const toggleTrigger = () => {