From 821a5b85c2a3462c4632569c6b39d7d7e1698bdb Mon Sep 17 00:00:00 2001 From: Sivin Varghese <64252451+iamsivin@users.noreply.github.com> Date: Tue, 13 Jan 2026 14:00:26 +0530 Subject: [PATCH] feat: Add conversations summary CSV export (#13110) # Pull Request Template ## Description This PR adds support for exporting conversation summary reports as CSV. Previously, the Conversations report incorrectly showed an option to download agent reports; this has now been fixed to export conversation-level data instead. Fixes https://linear.app/chatwoot/issue/CW-6176/conversation-reports-export-button-exports-agent-reports-instead ## Type of change - [x] Bug fix (non-breaking change which fixes an issue) - [x] New feature (non-breaking change which adds functionality) ## How Has This Been Tested? ### Screenshot image ## Checklist: - [x] My code follows the style guidelines of this project - [x] I have performed a self-review of my code - [ ] I have commented on my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [x] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [ ] Any dependent changes have been merged and published in downstream modules Co-authored-by: Muhsin Keloth --- .../api/v2/accounts/reports_controller.rb | 5 +++++ app/helpers/api/v2/accounts/reports_helper.rb | 19 ++++++++++++++++++ app/javascript/dashboard/api/reports.js | 6 ++++++ .../dashboard/i18n/locale/en/report.json | 2 +- .../dashboard/settings/reports/Index.vue | 10 +++++----- .../dashboard/store/modules/reports.js | 13 ++++++++++++ .../modules/specs/reports/actions.spec.js | 20 +++++++++++++++++++ .../reports/conversations_summary.csv.erb | 16 +++++++++++++++ config/locales/en.yml | 8 ++++++++ config/routes.rb | 1 + 10 files changed, 94 insertions(+), 6 deletions(-) create mode 100644 app/views/api/v2/accounts/reports/conversations_summary.csv.erb diff --git a/app/controllers/api/v2/accounts/reports_controller.rb b/app/controllers/api/v2/accounts/reports_controller.rb index 6e2d0ff4c..714aeb0c9 100644 --- a/app/controllers/api/v2/accounts/reports_controller.rb +++ b/app/controllers/api/v2/accounts/reports_controller.rb @@ -38,6 +38,11 @@ class Api::V2::Accounts::ReportsController < Api::V1::Accounts::BaseController generate_csv('teams_report', 'api/v2/accounts/reports/teams') end + def conversations_summary + @report_data = generate_conversations_report + generate_csv('conversations_summary_report', 'api/v2/accounts/reports/conversations_summary') + end + def conversation_traffic @report_data = generate_conversations_heatmap_report timezone_offset = (params[:timezone_offset] || 0).to_f diff --git a/app/helpers/api/v2/accounts/reports_helper.rb b/app/helpers/api/v2/accounts/reports_helper.rb index 23694d08d..1f34d7e97 100644 --- a/app/helpers/api/v2/accounts/reports_helper.rb +++ b/app/helpers/api/v2/accounts/reports_helper.rb @@ -46,6 +46,13 @@ module Api::V2::Accounts::ReportsHelper end end + def generate_conversations_report + builder = V2::Reports::Conversations::MetricBuilder.new(Current.account, build_params(type: :account)) + summary = builder.summary + + [generate_conversation_report_metrics(summary)] + end + private def build_params(base_params) @@ -71,4 +78,16 @@ module Api::V2::Accounts::ReportsHelper report[:resolved_conversations_count] ] end + + def generate_conversation_report_metrics(summary) + [ + summary[:conversations_count], + summary[:incoming_messages_count], + summary[:outgoing_messages_count], + Reports::TimeFormatPresenter.new(summary[:avg_first_response_time]).format, + Reports::TimeFormatPresenter.new(summary[:avg_resolution_time]).format, + summary[:resolutions_count], + Reports::TimeFormatPresenter.new(summary[:reply_time]).format + ] + end end diff --git a/app/javascript/dashboard/api/reports.js b/app/javascript/dashboard/api/reports.js index c87dfc82b..00f040f8e 100644 --- a/app/javascript/dashboard/api/reports.js +++ b/app/javascript/dashboard/api/reports.js @@ -61,6 +61,12 @@ class ReportsAPI extends ApiClient { }); } + getConversationsSummaryReports({ from: since, to: until, businessHours }) { + return axios.get(`${this.url}/conversations_summary`, { + params: { since, until, business_hours: businessHours }, + }); + } + getConversationTrafficCSV({ daysBefore = 6 } = {}) { return axios.get(`${this.url}/conversation_traffic`, { params: { timezone_offset: getTimeOffset(), days_before: daysBefore }, diff --git a/app/javascript/dashboard/i18n/locale/en/report.json b/app/javascript/dashboard/i18n/locale/en/report.json index dbf59f603..91eda0af0 100644 --- a/app/javascript/dashboard/i18n/locale/en/report.json +++ b/app/javascript/dashboard/i18n/locale/en/report.json @@ -3,7 +3,7 @@ "HEADER": "Conversations", "LOADING_CHART": "Loading chart data...", "NO_ENOUGH_DATA": "We've not received enough data points to generate report, Please try again later.", - "DOWNLOAD_AGENT_REPORTS": "Download agent reports", + "DOWNLOAD_CONVERSATION_REPORTS": "Download conversation reports", "DATA_FETCHING_FAILED": "Failed to fetch data, please try again later.", "SUMMARY_FETCHING_FAILED": "Failed to fetch summary, please try again later.", "METRICS": { diff --git a/app/javascript/dashboard/routes/dashboard/settings/reports/Index.vue b/app/javascript/dashboard/routes/dashboard/settings/reports/Index.vue index 0cade8635..bf45fe7b4 100644 --- a/app/javascript/dashboard/routes/dashboard/settings/reports/Index.vue +++ b/app/javascript/dashboard/routes/dashboard/settings/reports/Index.vue @@ -76,14 +76,14 @@ export default { businessHours, }; }, - downloadAgentReports() { + downloadConversationReports() { const { from, to } = this; const fileName = generateFileName({ - type: 'agent', + type: 'conversation', to, businessHours: this.businessHours, }); - this.$store.dispatch('downloadAgentReports', { + this.$store.dispatch('downloadConversationsSummaryReports', { from, to, fileName, @@ -109,10 +109,10 @@ export default {