Merge branch 'develop' into send-on-email-service

This commit is contained in:
Pranav
2025-10-19 10:09:32 -07:00
committed by GitHub
12 changed files with 49 additions and 25 deletions
+22 -16
View File
@@ -10,10 +10,28 @@ class V2::Reports::BaseSummaryBuilder
def load_data
@conversations_count = fetch_conversations_count
@resolved_count = fetch_resolved_count
@avg_resolution_time = fetch_average_time('conversation_resolved')
@avg_first_response_time = fetch_average_time('first_response')
@avg_reply_time = fetch_average_time('reply_time')
load_reporting_events_data
end
def load_reporting_events_data
# Extract the column name for indexing (e.g., 'conversations.team_id' -> 'team_id')
index_key = group_by_key.to_s.split('.').last
results = reporting_events
.select(
"#{group_by_key} as #{index_key}",
"COUNT(CASE WHEN name = 'conversation_resolved' THEN 1 END) as resolved_count",
"AVG(CASE WHEN name = 'conversation_resolved' THEN #{average_value_key} END) as avg_resolution_time",
"AVG(CASE WHEN name = 'first_response' THEN #{average_value_key} END) as avg_first_response_time",
"AVG(CASE WHEN name = 'reply_time' THEN #{average_value_key} END) as avg_reply_time"
)
.group(group_by_key)
.index_by { |record| record.public_send(index_key) }
@resolved_count = results.transform_values(&:resolved_count)
@avg_resolution_time = results.transform_values(&:avg_resolution_time)
@avg_first_response_time = results.transform_values(&:avg_first_response_time)
@avg_reply_time = results.transform_values(&:avg_reply_time)
end
def reporting_events
@@ -24,14 +42,6 @@ class V2::Reports::BaseSummaryBuilder
# Override this method
end
def fetch_average_time(event_name)
get_grouped_average(reporting_events.where(name: event_name))
end
def fetch_resolved_count
reporting_events.where(name: 'conversation_resolved').group(group_by_key).count
end
def group_by_key
# Override this method
end
@@ -40,10 +50,6 @@ class V2::Reports::BaseSummaryBuilder
# Override this method
end
def get_grouped_average(events)
events.group(group_by_key).average(average_value_key)
end
def average_value_key
ActiveModel::Type::Boolean.new.cast(params[:business_hours]).present? ? :value_in_business_hours : :value
end
@@ -13,10 +13,7 @@ class V2::Reports::InboxSummaryBuilder < V2::Reports::BaseSummaryBuilder
def load_data
@conversations_count = fetch_conversations_count
@resolved_count = fetch_resolved_count
@avg_resolution_time = fetch_average_time('conversation_resolved')
@avg_first_response_time = fetch_average_time('first_response')
@avg_reply_time = fetch_average_time('reply_time')
load_reporting_events_data
end
def fetch_conversations_count
@@ -1,4 +1,5 @@
<script setup>
import { useAccount } from 'dashboard/composables/useAccount';
import EmptyStateLayout from 'dashboard/components-next/EmptyStateLayout.vue';
import Button from 'dashboard/components-next/button/Button.vue';
import AssistantCard from 'dashboard/components-next/captain/assistant/AssistantCard.vue';
@@ -6,6 +7,7 @@ import FeatureSpotlight from 'dashboard/components-next/feature-spotlight/Featur
import { assistantsList } from 'dashboard/components-next/captain/pageComponents/emptyStates/captainEmptyStateContent.js';
const emit = defineEmits(['click']);
const { isOnChatwootCloud } = useAccount();
const onClick = () => {
emit('click');
@@ -20,6 +22,7 @@ const onClick = () => {
fallback-thumbnail-dark="/assets/images/dashboard/captain/assistant-dark.svg"
learn-more-url="https://chwt.app/captain-assistant"
class="mb-8"
:hide-actions="!isOnChatwootCloud"
/>
<EmptyStateLayout
:title="$t('CAPTAIN.ASSISTANTS.EMPTY_STATE.TITLE')"
@@ -1,4 +1,5 @@
<script setup>
import { useAccount } from 'dashboard/composables/useAccount';
import EmptyStateLayout from 'dashboard/components-next/EmptyStateLayout.vue';
import Button from 'dashboard/components-next/button/Button.vue';
import DocumentCard from 'dashboard/components-next/captain/assistant/DocumentCard.vue';
@@ -6,6 +7,7 @@ import FeatureSpotlight from 'dashboard/components-next/feature-spotlight/Featur
import { documentsList } from 'dashboard/components-next/captain/pageComponents/emptyStates/captainEmptyStateContent.js';
const emit = defineEmits(['click']);
const { isOnChatwootCloud } = useAccount();
const onClick = () => {
emit('click');
@@ -19,6 +21,7 @@ const onClick = () => {
fallback-thumbnail="/assets/images/dashboard/captain/document-light.svg"
fallback-thumbnail-dark="/assets/images/dashboard/captain/document-dark.svg"
learn-more-url="https://chwt.app/captain-document"
:hide-actions="!isOnChatwootCloud"
class="mb-8"
/>
<EmptyStateLayout
@@ -1,4 +1,5 @@
<script setup>
import { useAccount } from 'dashboard/composables/useAccount';
import EmptyStateLayout from 'dashboard/components-next/EmptyStateLayout.vue';
import Button from 'dashboard/components-next/button/Button.vue';
import ResponseCard from 'dashboard/components-next/captain/assistant/ResponseCard.vue';
@@ -6,6 +7,7 @@ import FeatureSpotlight from 'dashboard/components-next/feature-spotlight/Featur
import { responsesList } from 'dashboard/components-next/captain/pageComponents/emptyStates/captainEmptyStateContent.js';
const emit = defineEmits(['click']);
const { isOnChatwootCloud } = useAccount();
const onClick = () => {
emit('click');
@@ -19,6 +21,7 @@ const onClick = () => {
fallback-thumbnail="/assets/images/dashboard/captain/faqs-light.svg"
fallback-thumbnail-dark="/assets/images/dashboard/captain/faqs-dark.svg"
learn-more-url="https://chwt.app/captain-faq"
:hide-actions="!isOnChatwootCloud"
class="mb-8"
/>
<EmptyStateLayout
@@ -10,6 +10,7 @@ defineProps({
fallbackThumbnail: { type: String, default: '' },
fallbackThumbnailDark: { type: String, default: '' },
learnMoreUrl: { type: String, default: '' },
hideActions: { type: Boolean, default: false },
});
const imageError = ref(false);
@@ -65,7 +66,7 @@ const openLink = link => {
<div class="flex flex-col flex-1 gap-3 ltr:pr-8 rtl:pl-8">
<p v-if="note" class="text-n-slate-12 text-sm mb-0">{{ note }}</p>
<div class="flex gap-3">
<div v-if="!hideActions" class="flex gap-3">
<slot name="actions">
<Button
v-if="videoUrl"
@@ -13,6 +13,7 @@ defineProps({
fallbackThumbnail: { type: String, default: '' },
fallbackThumbnailDark: { type: String, default: '' },
learnMoreUrl: { type: String, default: '' },
hideActions: { type: Boolean, default: false },
});
const imageError = ref(false);
@@ -92,7 +93,7 @@ const openLink = link => {
{{ note }}
</p>
<div class="flex gap-3 justify-between w-full">
<div v-if="!hideActions" class="flex gap-3 justify-between w-full">
<slot name="actions">
<Button
v-if="videoUrl"
@@ -2,6 +2,8 @@
import { computed, onMounted, ref, nextTick } from 'vue';
import { useMapGetter, useStore } from 'dashboard/composables/store';
import { FEATURE_FLAGS } from 'dashboard/featureFlags';
import { useRouter } from 'vue-router';
import { useAccount } from 'dashboard/composables/useAccount';
import AssistantCard from 'dashboard/components-next/captain/assistant/AssistantCard.vue';
import DeleteDialog from 'dashboard/components-next/captain/pageComponents/DeleteDialog.vue';
@@ -11,7 +13,8 @@ import CreateAssistantDialog from 'dashboard/components-next/captain/pageCompone
import AssistantPageEmptyState from 'dashboard/components-next/captain/pageComponents/emptyStates/AssistantPageEmptyState.vue';
import FeatureSpotlightPopover from 'dashboard/components-next/feature-spotlight/FeatureSpotlightPopover.vue';
import LimitBanner from 'dashboard/components-next/captain/pageComponents/response/LimitBanner.vue';
import { useRouter } from 'vue-router';
const { isOnChatwootCloud } = useAccount();
const router = useRouter();
@@ -90,6 +93,7 @@ onMounted(() => store.dispatch('captainAssistants/get'));
:button-label="$t('CAPTAIN.HEADER_KNOW_MORE')"
:title="$t('CAPTAIN.ASSISTANTS.EMPTY_STATE.FEATURE_SPOTLIGHT.TITLE')"
:note="$t('CAPTAIN.ASSISTANTS.EMPTY_STATE.FEATURE_SPOTLIGHT.NOTE')"
:hide-actions="!isOnChatwootCloud"
fallback-thumbnail="/assets/images/dashboard/captain/assistant-popover-light.svg"
fallback-thumbnail-dark="/assets/images/dashboard/captain/assistant-popover-dark.svg"
learn-more-url="https://chwt.app/captain-assistant"
@@ -2,6 +2,7 @@
import { computed, onMounted, ref, nextTick } from 'vue';
import { useMapGetter, useStore } from 'dashboard/composables/store';
import { FEATURE_FLAGS } from 'dashboard/featureFlags';
import { useAccount } from 'dashboard/composables/useAccount';
import DeleteDialog from 'dashboard/components-next/captain/pageComponents/DeleteDialog.vue';
import DocumentCard from 'dashboard/components-next/captain/assistant/DocumentCard.vue';
@@ -16,6 +17,7 @@ import LimitBanner from 'dashboard/components-next/captain/pageComponents/docume
const store = useStore();
const { isOnChatwootCloud } = useAccount();
const uiFlags = useMapGetter('captainDocuments/getUIFlags');
const documents = useMapGetter('captainDocuments/getRecords');
const assistants = useMapGetter('captainAssistants/getRecords');
@@ -121,6 +123,7 @@ onMounted(() => {
:button-label="$t('CAPTAIN.HEADER_KNOW_MORE')"
:title="$t('CAPTAIN.DOCUMENTS.EMPTY_STATE.FEATURE_SPOTLIGHT.TITLE')"
:note="$t('CAPTAIN.DOCUMENTS.EMPTY_STATE.FEATURE_SPOTLIGHT.NOTE')"
:hide-actions="!isOnChatwootCloud"
fallback-thumbnail="/assets/images/dashboard/captain/document-popover-light.svg"
fallback-thumbnail-dark="/assets/images/dashboard/captain/document-popover-dark.svg"
learn-more-url="https://chwt.app/captain-document"
@@ -7,6 +7,7 @@ import { OnClickOutside } from '@vueuse/components';
import { useRouter } from 'vue-router';
import { FEATURE_FLAGS } from 'dashboard/featureFlags';
import { debounce } from '@chatwoot/utils';
import { useAccount } from 'dashboard/composables/useAccount';
import Button from 'dashboard/components-next/button/Button.vue';
import Checkbox from 'dashboard/components-next/checkbox/Checkbox.vue';
@@ -25,6 +26,7 @@ import LimitBanner from 'dashboard/components-next/captain/pageComponents/respon
const router = useRouter();
const store = useStore();
const { isOnChatwootCloud } = useAccount();
const uiFlags = useMapGetter('captainResponses/getUIFlags');
const assistants = useMapGetter('captainAssistants/getRecords');
const responseMeta = useMapGetter('captainResponses/getMeta');
@@ -285,6 +287,7 @@ onMounted(() => {
:button-label="$t('CAPTAIN.HEADER_KNOW_MORE')"
:title="$t('CAPTAIN.RESPONSES.EMPTY_STATE.FEATURE_SPOTLIGHT.TITLE')"
:note="$t('CAPTAIN.RESPONSES.EMPTY_STATE.FEATURE_SPOTLIGHT.NOTE')"
:hide-actions="!isOnChatwootCloud"
fallback-thumbnail="/assets/images/dashboard/captain/faqs-popover-light.svg"
fallback-thumbnail-dark="/assets/images/dashboard/captain/faqs-popover-dark.svg"
learn-more-url="https://chwt.app/captain-faq"
+1 -1
View File
@@ -1,5 +1,5 @@
shared: &shared
version: '4.6.0'
version: '4.7.0'
development:
<<: *shared
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@chatwoot/chatwoot",
"version": "4.6.0",
"version": "4.7.0",
"license": "MIT",
"scripts": {
"eslint": "eslint app/**/*.{js,vue}",