From 1c7435f21bc7594b6e48c1c3450a1b211d2d277d Mon Sep 17 00:00:00 2001 From: Kevin Aleman Date: Mon, 18 Oct 2021 16:45:46 -0600 Subject: [PATCH 1/7] Show on hold metrics on analytics pages --- app/livechat/imports/server/rest/rooms.js | 3 +- app/livechat/server/api/lib/rooms.js | 2 + app/livechat/server/lib/Analytics.js | 4 ++ .../server/lib/analytics/dashboards.js | 2 +- app/models/server/models/LivechatRooms.js | 13 +++++ app/models/server/raw/LivechatRooms.js | 9 +++- .../currentChats/CurrentChatsRoute.tsx | 50 +++++++++++-------- .../omnichannel/currentChats/FilterByText.tsx | 3 +- .../livechat-enterprise/server/api/rooms.ts | 4 ++ packages/rocketchat-i18n/i18n/en.i18n.json | 1 + packages/rocketchat-i18n/i18n/es.i18n.json | 3 +- 11 files changed, 69 insertions(+), 25 deletions(-) diff --git a/app/livechat/imports/server/rest/rooms.js b/app/livechat/imports/server/rest/rooms.js index d2f4c6e20d63f..1c43cad677a09 100644 --- a/app/livechat/imports/server/rest/rooms.js +++ b/app/livechat/imports/server/rest/rooms.js @@ -21,7 +21,7 @@ API.v1.addRoute('livechat/rooms', { authRequired: true }, { get() { const { offset, count } = this.getPaginationItems(); const { sort, fields } = this.parseJsonQuery(); - const { agents, departmentId, open, tags, roomName } = this.requestParams(); + const { agents, departmentId, open, tags, roomName, onhold } = this.requestParams(); let { createdAt, customFields, closedAt } = this.requestParams(); check(agents, Match.Maybe([String])); check(roomName, Match.Maybe(String)); @@ -51,6 +51,7 @@ API.v1.addRoute('livechat/rooms', { authRequired: true }, { closedAt, tags, customFields, + onhold, options: { offset, count, sort, fields }, }))); }, diff --git a/app/livechat/server/api/lib/rooms.js b/app/livechat/server/api/lib/rooms.js index 72d84803de153..957911737f0aa 100644 --- a/app/livechat/server/api/lib/rooms.js +++ b/app/livechat/server/api/lib/rooms.js @@ -9,6 +9,7 @@ export async function findRooms({ closedAt, tags, customFields, + onhold, options: { offset, count, @@ -25,6 +26,7 @@ export async function findRooms({ closedAt, tags, customFields, + onhold: ['t', 'true', '1'].includes(onhold), options: { sort: sort || { ts: -1 }, offset, diff --git a/app/livechat/server/lib/Analytics.js b/app/livechat/server/lib/Analytics.js index c4251fbd1bce1..595902e0f155b 100644 --- a/app/livechat/server/lib/Analytics.js +++ b/app/livechat/server/lib/Analytics.js @@ -337,6 +337,7 @@ export const Analytics = { to: utcBusiestHour >= 0 ? moment.utc().set({ hour: utcBusiestHour }).tz(timezone).format('hA') : '-', from: utcBusiestHour >= 0 ? moment.utc().set({ hour: utcBusiestHour }).subtract(1, 'hour').tz(timezone).format('hA') : '', }; + const onHoldConversations = LivechatRooms.getOnHoldConversationsBetweenDate(from, to); const data = [{ title: 'Total_conversations', @@ -344,6 +345,9 @@ export const Analytics = { }, { title: 'Open_conversations', value: openConversations, + }, { + title: 'On_Hold_conversations', + value: onHoldConversations, }, { title: 'Total_messages', value: totalMessages, diff --git a/app/livechat/server/lib/analytics/dashboards.js b/app/livechat/server/lib/analytics/dashboards.js index 18bdca6300332..e37ef72ff5021 100644 --- a/app/livechat/server/lib/analytics/dashboards.js +++ b/app/livechat/server/lib/analytics/dashboards.js @@ -193,7 +193,7 @@ const getConversationsMetricsAsync = async ({ utcOffset: user.utcOffset, language: user.language || settings.get('Language') || 'en', }); - const metrics = ['Total_conversations', 'Open_conversations', 'Total_messages']; + const metrics = ['Total_conversations', 'Open_conversations', 'On_Hold_conversations', 'Total_messages']; const visitorsCount = await LivechatVisitors.getVisitorsBetweenDate({ start, end, department: departmentId }).count(); return { totalizers: [ diff --git a/app/models/server/models/LivechatRooms.js b/app/models/server/models/LivechatRooms.js index 1d71be35aad0b..0b9bc2f4b013e 100644 --- a/app/models/server/models/LivechatRooms.js +++ b/app/models/server/models/LivechatRooms.js @@ -448,6 +448,19 @@ export class LivechatRooms extends Base { return this.find(query, { fields: { ts: 1, departmentId: 1, open: 1, servedBy: 1, metrics: 1, msgs: 1 } }); } + getOnHoldConversationsBetweenDate(from, to) { + return this.find({ + onHold: { + $exists: true, + $eq: true, + }, + ts: { + $gte: new Date(from), // ISO Date, ts >= date.gte + $lt: new Date(to), // ISODate, ts < date.lt + }, + }).count(); + } + getAnalyticsMetricsBetweenDateWithMessages(t, date, { departmentId } = {}, extraQuery) { return this.model.rawCollection().aggregate([ { diff --git a/app/models/server/raw/LivechatRooms.js b/app/models/server/raw/LivechatRooms.js index 0c07e12add2be..5ba508fbfc8fe 100644 --- a/app/models/server/raw/LivechatRooms.js +++ b/app/models/server/raw/LivechatRooms.js @@ -896,7 +896,7 @@ export class LivechatRoomsRaw extends BaseRaw { return this.col.aggregate(params); } - findRoomsWithCriteria({ agents, roomName, departmentId, open, served, createdAt, closedAt, tags, customFields, visitorId, roomIds, options = {} }) { + findRoomsWithCriteria({ agents, roomName, departmentId, open, served, createdAt, closedAt, tags, customFields, visitorId, roomIds, onhold, options = {} }) { const query = { t: 'l', }; @@ -947,6 +947,13 @@ export class LivechatRoomsRaw extends BaseRaw { query._id = { $in: roomIds }; } + if (onhold) { + query.onHold = { + $exists: true, + $eq: onhold, + }; + } + return this.find(query, { sort: options.sort || { name: 1 }, skip: options.offset, limit: options.count }); } diff --git a/client/views/omnichannel/currentChats/CurrentChatsRoute.tsx b/client/views/omnichannel/currentChats/CurrentChatsRoute.tsx index 7e766e4c00f4f..4bf9e123be84b 100644 --- a/client/views/omnichannel/currentChats/CurrentChatsRoute.tsx +++ b/client/views/omnichannel/currentChats/CurrentChatsRoute.tsx @@ -47,6 +47,7 @@ const useQuery: useQueryType = ( departmentId?: string; tags?: string[]; customFields?: string; + onhold?: boolean; } = { ...(guest && { roomName: guest }), sort: JSON.stringify({ @@ -71,8 +72,10 @@ const useQuery: useQueryType = ( }), }); } + if (status !== 'all') { - query.open = status === 'opened'; + query.open = status === 'opened' || status === 'onhold'; + query.onhold = status === 'onhold'; } if (servedBy && servedBy !== 'all') { query.agents = [servedBy]; @@ -215,25 +218,32 @@ const CurrentChatsRoute: FC = () => { ); const renderRow = useCallback( - ({ _id, fname, servedBy, ts, lm, department, open }) => ( - onRowClick(_id)} - action - qa-user-id={_id} - > - {fname} - {department ? department.name : ''} - {servedBy && servedBy.username} - {moment(ts).format('L LTS')} - {moment(lm).format('L LTS')} - {open ? t('Open') : t('Closed')} - {canRemoveClosedChats && !open && } - - ), - [onRowClick, reload, t, canRemoveClosedChats], + ({ _id, fname, servedBy, ts, lm, department, open, onHold }) => { + const getStatusText = (open: boolean, onHold: boolean): string => { + if (!open) return t('Closed'); + return onHold ? t('On_Hold_Chats') : t('Open'); + }; + + return ( + onRowClick(_id)} + action + qa-user-id={_id} + > + {fname} + {department ? department.name : ''} + {servedBy && servedBy.username} + {moment(ts).format('L LTS')} + {moment(lm).format('L LTS')} + {getStatusText(open, onHold)} + {canRemoveClosedChats && !open && } + + ); + }, + [onRowClick, reload, canRemoveClosedChats, t], ); if (!canViewCurrentChats) { diff --git a/client/views/omnichannel/currentChats/FilterByText.tsx b/client/views/omnichannel/currentChats/FilterByText.tsx index 6a2445da147d0..eb40b39f02a15 100644 --- a/client/views/omnichannel/currentChats/FilterByText.tsx +++ b/client/views/omnichannel/currentChats/FilterByText.tsx @@ -31,6 +31,7 @@ const FilterByText: FilterByTextType = ({ setFilter, reload, ...props }) => { ['all', t('All')], ['closed', t('Closed')], ['opened', t('Open')], + ['onhold', t('On_Hold_Chats')], ]; const customFieldsOptions: [string, string][] = useMemo( () => @@ -110,7 +111,7 @@ const FilterByText: FilterByTextType = ({ setFilter, reload, ...props }) => { reload && reload(); dispatchToastMessage({ type: 'success', message: t('Chat_removed') }); } catch (error) { - dispatchToastMessage({ type: 'error', message: error }); + dispatchToastMessage({ type: 'error', message: (error as Error).message }); } setModal(null); }; diff --git a/ee/app/livechat-enterprise/server/api/rooms.ts b/ee/app/livechat-enterprise/server/api/rooms.ts index 317ae751b2c19..c41a2ae8cdfad 100644 --- a/ee/app/livechat-enterprise/server/api/rooms.ts +++ b/ee/app/livechat-enterprise/server/api/rooms.ts @@ -32,6 +32,10 @@ API.v1.addRoute('livechat/room.onHold', { authRequired: true }, { return API.v1.failure('Room is already On-Hold'); } + if (!room.open) { + return API.v1.failure('Room cannot be placed on hold after being closed'); + } + const user = Meteor.user(); if (!user) { return API.v1.failure('Invalid user'); diff --git a/packages/rocketchat-i18n/i18n/en.i18n.json b/packages/rocketchat-i18n/i18n/en.i18n.json index 4a7c532e158e4..08243e815b024 100644 --- a/packages/rocketchat-i18n/i18n/en.i18n.json +++ b/packages/rocketchat-i18n/i18n/en.i18n.json @@ -3178,6 +3178,7 @@ "Omnichannel_External_Frame_URL": "External frame URL", "On": "On", "On_Hold_Chats": "On Hold", + "On_Hold_conversations": "On hold conversations", "online": "online", "Online": "Online", "Only_authorized_users_can_write_new_messages": "Only authorized users can write new messages", diff --git a/packages/rocketchat-i18n/i18n/es.i18n.json b/packages/rocketchat-i18n/i18n/es.i18n.json index d4856285febc3..2a1249b682ac7 100644 --- a/packages/rocketchat-i18n/i18n/es.i18n.json +++ b/packages/rocketchat-i18n/i18n/es.i18n.json @@ -773,7 +773,7 @@ "Chat_History": "Historial del chat", "Chat_Now": "Chatea ahora", "chat_on_hold_due_to_inactivity": "Este chat está en espera por inactividad", - "Chat_On_Hold": "Chant en espera", + "Chat_On_Hold": "Chat en espera", "Chat_On_Hold_Successfully": "Este chat se puso correctamente en espera", "Chat_queued": "Chat en cola", "Chat_removed": "Chat eliminado", @@ -3120,6 +3120,7 @@ "Omnichannel_External_Frame_URL": "URL del marco externo", "On": "Activar", "On_Hold_Chats": "En espera", + "On_Hold_conversations": "Conversaciones en espera", "online": "en línea", "Online": "Conectado", "Only_authorized_users_can_write_new_messages": "Sólo los usuarios autorizados pueden escribir nuevos mensajes", From a905aa6ee4670acd454386daeed188b461db9dcc Mon Sep 17 00:00:00 2001 From: Kevin Aleman Date: Tue, 19 Oct 2021 08:41:20 -0600 Subject: [PATCH 2/7] Add onhold chats to graphs --- app/livechat/server/lib/Analytics.js | 7 ++- .../server/lib/analytics/dashboards.js | 10 ++++- app/models/server/models/LivechatRooms.js | 13 ------ app/models/server/raw/LivechatRooms.js | 44 +++++++++++++++++++ .../realTimeMonitoring/charts/ChatsChart.js | 8 ++-- .../charts/ChatsPerAgentChart.js | 4 +- 6 files changed, 63 insertions(+), 23 deletions(-) diff --git a/app/livechat/server/lib/Analytics.js b/app/livechat/server/lib/Analytics.js index 595902e0f155b..31ccc226a7d70 100644 --- a/app/livechat/server/lib/Analytics.js +++ b/app/livechat/server/lib/Analytics.js @@ -2,6 +2,7 @@ import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; import moment from 'moment'; import { LivechatRooms } from '../../../models'; +import { LivechatRooms as LivechatRoomsRaw } from '../../../models/server/raw'; import { secondsToHHMMSS } from '../../../utils/server'; import { getTimezone } from '../../../utils/server/lib/getTimezone'; import { Logger } from '../../../logger'; @@ -337,9 +338,9 @@ export const Analytics = { to: utcBusiestHour >= 0 ? moment.utc().set({ hour: utcBusiestHour }).tz(timezone).format('hA') : '-', from: utcBusiestHour >= 0 ? moment.utc().set({ hour: utcBusiestHour }).subtract(1, 'hour').tz(timezone).format('hA') : '', }; - const onHoldConversations = LivechatRooms.getOnHoldConversationsBetweenDate(from, to); + const onHoldConversations = Promise.await(LivechatRoomsRaw.getOnHoldConversationsBetweenDate(from, to, departmentId)); - const data = [{ + return [{ title: 'Total_conversations', value: totalConversations, }, { @@ -361,8 +362,6 @@ export const Analytics = { title: 'Busiest_time', value: `${ busiestHour.from }${ busiestHour.to ? `- ${ busiestHour.to }` : '' }`, }]; - - return data; }, /** diff --git a/app/livechat/server/lib/analytics/dashboards.js b/app/livechat/server/lib/analytics/dashboards.js index e37ef72ff5021..70dc1c7925ff8 100644 --- a/app/livechat/server/lib/analytics/dashboards.js +++ b/app/livechat/server/lib/analytics/dashboards.js @@ -25,6 +25,7 @@ const findAllChatsStatusAsync = async ({ open: await LivechatRooms.countAllOpenChatsBetweenDate({ start, end, departmentId }), closed: await LivechatRooms.countAllClosedChatsBetweenDate({ start, end, departmentId }), queued: await LivechatRooms.countAllQueuedChatsBetweenDate({ start, end, departmentId }), + onhold: await LivechatRooms.getOnHoldConversationsBetweenDate(start, end, departmentId), }; }; @@ -213,13 +214,20 @@ const findAllChatMetricsByAgentAsync = async ({ } const open = await LivechatRooms.countAllOpenChatsByAgentBetweenDate({ start, end, departmentId }); const closed = await LivechatRooms.countAllClosedChatsByAgentBetweenDate({ start, end, departmentId }); + const onhold = await LivechatRooms.countAllOnHoldChatsByAgentBetweenDate({ start, end, departmentId }); const result = {}; (open || []).forEach((agent) => { - result[agent._id] = { open: agent.chats, closed: 0 }; + result[agent._id] = { open: agent.chats, closed: 0, onhold: 0 }; }); (closed || []).forEach((agent) => { result[agent._id] = { open: result[agent._id] ? result[agent._id].open : 0, closed: agent.chats }; }); + (onhold || []).forEach((agent) => { + result[agent._id] = { + ...result[agent._id], + onhold: agent.chats, + }; + }); return result; }; diff --git a/app/models/server/models/LivechatRooms.js b/app/models/server/models/LivechatRooms.js index 0b9bc2f4b013e..1d71be35aad0b 100644 --- a/app/models/server/models/LivechatRooms.js +++ b/app/models/server/models/LivechatRooms.js @@ -448,19 +448,6 @@ export class LivechatRooms extends Base { return this.find(query, { fields: { ts: 1, departmentId: 1, open: 1, servedBy: 1, metrics: 1, msgs: 1 } }); } - getOnHoldConversationsBetweenDate(from, to) { - return this.find({ - onHold: { - $exists: true, - $eq: true, - }, - ts: { - $gte: new Date(from), // ISO Date, ts >= date.gte - $lt: new Date(to), // ISODate, ts < date.lt - }, - }).count(); - } - getAnalyticsMetricsBetweenDateWithMessages(t, date, { departmentId } = {}, extraQuery) { return this.model.rawCollection().aggregate([ { diff --git a/app/models/server/raw/LivechatRooms.js b/app/models/server/raw/LivechatRooms.js index 5ba508fbfc8fe..08d439e82bc42 100644 --- a/app/models/server/raw/LivechatRooms.js +++ b/app/models/server/raw/LivechatRooms.js @@ -536,6 +536,31 @@ export class LivechatRoomsRaw extends BaseRaw { return this.col.aggregate([match, group]).toArray(); } + countAllOnHoldChatsByAgentBetweenDate({ start, end, departmentId }) { + const match = { + $match: { + t: 'l', + 'servedBy.username': { $exists: true }, + open: true, + onHold: { + $exists: true, + $eq: true, + }, + ts: { $gte: new Date(start), $lte: new Date(end) }, + }, + }; + const group = { + $group: { + _id: '$servedBy.username', + chats: { $sum: 1 }, + }, + }; + if (departmentId && departmentId !== 'undefined') { + match.$match.departmentId = departmentId; + } + return this.col.aggregate([match, group]).toArray(); + } + countAllClosedChatsByAgentBetweenDate({ start, end, departmentId }) { const match = { $match: { @@ -957,6 +982,25 @@ export class LivechatRoomsRaw extends BaseRaw { return this.find(query, { sort: options.sort || { name: 1 }, skip: options.offset, limit: options.count }); } + getOnHoldConversationsBetweenDate(from, to, departmentId) { + const query = { + onHold: { + $exists: true, + $eq: true, + }, + ts: { + $gte: new Date(from), // ISO Date, ts >= date.gte + $lt: new Date(to), // ISODate, ts < date.lt + }, + }; + + if (departmentId && departmentId !== 'undefined') { + query.departmentId = departmentId; + } + + return this.find(query).count(); + } + findAllServiceTimeByAgent({ start, end, onlyCount = false, options = {} }) { const match = { $match: { diff --git a/client/views/omnichannel/realTimeMonitoring/charts/ChatsChart.js b/client/views/omnichannel/realTimeMonitoring/charts/ChatsChart.js index 7fee07da730fd..d9b6594065ff5 100644 --- a/client/views/omnichannel/realTimeMonitoring/charts/ChatsChart.js +++ b/client/views/omnichannel/realTimeMonitoring/charts/ChatsChart.js @@ -7,12 +7,13 @@ import { useEndpointData } from '../../../../hooks/useEndpointData'; import Chart from './Chart'; import { useUpdateChartData } from './useUpdateChartData'; -const labels = ['Open', 'Queued', 'Closed']; +const labels = ['Open', 'Queued', 'Closed', 'On_Hold_Chats']; const initialData = { open: 0, queued: 0, closed: 0, + onhold: 0, }; const init = (canvas, context, t) => @@ -45,7 +46,7 @@ const ChatsChart = ({ params, reloadRef, ...props }) => { reloadRef.current.chatsChart = reload; - const { open, queued, closed } = data ?? initialData; + const { open, queued, closed, onhold } = data ?? initialData; useEffect(() => { const initChart = async () => { @@ -59,8 +60,9 @@ const ChatsChart = ({ params, reloadRef, ...props }) => { updateChartData(t('Open'), [open]); updateChartData(t('Closed'), [closed]); updateChartData(t('Queued'), [queued]); + updateChartData(t('On_Hold_Chats'), [onhold]); } - }, [closed, open, queued, state, t, updateChartData]); + }, [closed, open, queued, onhold, state, t, updateChartData]); return ; }; diff --git a/client/views/omnichannel/realTimeMonitoring/charts/ChatsPerAgentChart.js b/client/views/omnichannel/realTimeMonitoring/charts/ChatsPerAgentChart.js index 1092c7646b24c..07fd9ba6c94b0 100644 --- a/client/views/omnichannel/realTimeMonitoring/charts/ChatsPerAgentChart.js +++ b/client/views/omnichannel/realTimeMonitoring/charts/ChatsPerAgentChart.js @@ -12,7 +12,7 @@ const initialData = { }; const init = (canvas, context, t) => - drawLineChart(canvas, context, [t('Open'), t('Closed')], [], [[], []], { + drawLineChart(canvas, context, [t('Open'), t('Closed'), t('On_Hold_Chats')], [], [[], []], { legends: true, anim: true, smallTicks: true, @@ -53,7 +53,7 @@ const ChatsPerAgentChart = ({ params, reloadRef, ...props }) => { if (chartData && chartData.success) { delete chartData.success; Object.entries(chartData).forEach(([name, value]) => { - updateChartData(name, [value.open, value.closed]); + updateChartData(name, [value.open, value.closed, value.onhold]); }); } } From 7760b84e6aa2d33a908d79253bb66bf823da456b Mon Sep 17 00:00:00 2001 From: Kevin Aleman Date: Tue, 19 Oct 2021 08:44:10 -0600 Subject: [PATCH 3/7] make colors match cause ocd --- .../omnichannel/realTimeMonitoring/charts/ChatsChart.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/views/omnichannel/realTimeMonitoring/charts/ChatsChart.js b/client/views/omnichannel/realTimeMonitoring/charts/ChatsChart.js index d9b6594065ff5..38eba111c21ac 100644 --- a/client/views/omnichannel/realTimeMonitoring/charts/ChatsChart.js +++ b/client/views/omnichannel/realTimeMonitoring/charts/ChatsChart.js @@ -7,13 +7,13 @@ import { useEndpointData } from '../../../../hooks/useEndpointData'; import Chart from './Chart'; import { useUpdateChartData } from './useUpdateChartData'; -const labels = ['Open', 'Queued', 'Closed', 'On_Hold_Chats']; +const labels = ['Open', 'Queued', 'On_Hold_Chats', 'Closed']; const initialData = { open: 0, queued: 0, - closed: 0, onhold: 0, + closed: 0, }; const init = (canvas, context, t) => @@ -59,8 +59,8 @@ const ChatsChart = ({ params, reloadRef, ...props }) => { if (state === AsyncStatePhase.RESOLVED) { updateChartData(t('Open'), [open]); updateChartData(t('Closed'), [closed]); - updateChartData(t('Queued'), [queued]); updateChartData(t('On_Hold_Chats'), [onhold]); + updateChartData(t('Queued'), [queued]); } }, [closed, open, queued, onhold, state, t, updateChartData]); From 58fbd4063c39f3f4c8d56184bec9c20bf920d443 Mon Sep 17 00:00:00 2001 From: Kevin Aleman Date: Wed, 20 Oct 2021 13:48:53 -0600 Subject: [PATCH 4/7] change way of calculating open rooms to account for onhold chats --- app/livechat/server/lib/Analytics.js | 1 + app/models/server/models/LivechatRooms.js | 2 ++ app/models/server/raw/LivechatRooms.js | 22 +++++++++++++++++++++- 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/app/livechat/server/lib/Analytics.js b/app/livechat/server/lib/Analytics.js index 31ccc226a7d70..8d4cec9cd175b 100644 --- a/app/livechat/server/lib/Analytics.js +++ b/app/livechat/server/lib/Analytics.js @@ -306,6 +306,7 @@ export const Analytics = { lt: m.add(1, 'days'), }; const result = Promise.await(LivechatRooms.getAnalyticsBetweenDate(date, { departmentId }).toArray()); + console.log(result); totalConversations += result.length; result.forEach(summarize(clonedDate)); diff --git a/app/models/server/models/LivechatRooms.js b/app/models/server/models/LivechatRooms.js index 1d71be35aad0b..e0cd513491198 100644 --- a/app/models/server/models/LivechatRooms.js +++ b/app/models/server/models/LivechatRooms.js @@ -563,6 +563,7 @@ export class LivechatRooms extends Base { open: '$open', servedBy: '$servedBy', metrics: '$metrics', + onHold: '$onHold', }, messagesCount: { $sum: 1, @@ -578,6 +579,7 @@ export class LivechatRooms extends Base { servedBy: '$_id.servedBy', metrics: '$_id.metrics', msgs: '$messagesCount', + onHold: '$onHold', }, }, ]); diff --git a/app/models/server/raw/LivechatRooms.js b/app/models/server/raw/LivechatRooms.js index 08d439e82bc42..029e9224fcd3c 100644 --- a/app/models/server/raw/LivechatRooms.js +++ b/app/models/server/raw/LivechatRooms.js @@ -479,6 +479,16 @@ export class LivechatRoomsRaw extends BaseRaw { 'metrics.chatDuration': { $exists: false, }, + $or: [{ + onHold: { + $exists: false, + }, + }, { + onHold: { + $exists: true, + $eq: false, + }, + }], servedBy: { $exists: true }, ts: { $gte: new Date(start), $lte: new Date(end) }, }; @@ -494,7 +504,6 @@ export class LivechatRoomsRaw extends BaseRaw { 'metrics.chatDuration': { $exists: true, }, - servedBy: { $exists: true }, ts: { $gte: new Date(start), $lte: new Date(end) }, }; if (departmentId && departmentId !== 'undefined') { @@ -507,6 +516,7 @@ export class LivechatRoomsRaw extends BaseRaw { const query = { t: 'l', servedBy: { $exists: false }, + open: true, ts: { $gte: new Date(start), $lte: new Date(end) }, }; if (departmentId && departmentId !== 'undefined') { @@ -521,6 +531,16 @@ export class LivechatRoomsRaw extends BaseRaw { t: 'l', 'servedBy.username': { $exists: true }, open: true, + $or: [{ + onHold: { + $exists: false, + }, + }, { + onHold: { + $exists: true, + $eq: false, + }, + }], ts: { $gte: new Date(start), $lte: new Date(end) }, }, }; From 4e31a62918e4c180778e7caac74a7f9198ce1810 Mon Sep 17 00:00:00 2001 From: Kevin Aleman Date: Fri, 22 Oct 2021 12:11:57 -0600 Subject: [PATCH 5/7] remove onhold chats from open chats --- app/livechat/imports/server/rest/rooms.js | 1 + app/models/server/raw/LivechatRooms.js | 1 + 2 files changed, 2 insertions(+) diff --git a/app/livechat/imports/server/rest/rooms.js b/app/livechat/imports/server/rest/rooms.js index 1c43cad677a09..9680b8baffce1 100644 --- a/app/livechat/imports/server/rest/rooms.js +++ b/app/livechat/imports/server/rest/rooms.js @@ -27,6 +27,7 @@ API.v1.addRoute('livechat/rooms', { authRequired: true }, { check(roomName, Match.Maybe(String)); check(departmentId, Match.Maybe(String)); check(open, Match.Maybe(String)); + check(onhold, Match.Maybe(String)); check(tags, Match.Maybe([String])); const hasAdminAccess = hasPermission(this.userId, 'view-livechat-rooms'); diff --git a/app/models/server/raw/LivechatRooms.js b/app/models/server/raw/LivechatRooms.js index 029e9224fcd3c..c73a15e3ad5c2 100644 --- a/app/models/server/raw/LivechatRooms.js +++ b/app/models/server/raw/LivechatRooms.js @@ -956,6 +956,7 @@ export class LivechatRoomsRaw extends BaseRaw { } if (open !== undefined) { query.open = { $exists: open }; + query.onHold = { $ne: true }; } if (served !== undefined) { query.servedBy = { $exists: served }; From 08fff689e1571f52ddec6018197e5c4f092b3194 Mon Sep 17 00:00:00 2001 From: Kevin Aleman Date: Fri, 22 Oct 2021 12:25:53 -0600 Subject: [PATCH 6/7] fix colors --- app/livechat/client/lib/chartHandler.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/livechat/client/lib/chartHandler.js b/app/livechat/client/lib/chartHandler.js index 7af6388409b1d..f99571f0e66d0 100644 --- a/app/livechat/client/lib/chartHandler.js +++ b/app/livechat/client/lib/chartHandler.js @@ -194,9 +194,9 @@ export const drawDoughnutChart = async (chart, title, chartContext, dataLabels, data: dataPoints, // data points corresponding to data labels, x-axis points backgroundColor: [ '#2de0a5', - '#ffd21f', - '#f5455c', '#cbced1', + '#f5455c', + '#ffd21f', ], borderWidth: 0, }], From c503cafe27d9a80b677a14dafba7c5a93c16c61b Mon Sep 17 00:00:00 2001 From: Kevin Aleman Date: Mon, 25 Oct 2021 08:31:22 -0600 Subject: [PATCH 7/7] fix summarize to remove onhold conversations --- app/livechat/server/lib/Analytics.js | 5 ++--- app/models/server/models/LivechatRooms.js | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/app/livechat/server/lib/Analytics.js b/app/livechat/server/lib/Analytics.js index 8d4cec9cd175b..b4aa71af346f6 100644 --- a/app/livechat/server/lib/Analytics.js +++ b/app/livechat/server/lib/Analytics.js @@ -289,8 +289,8 @@ export const Analytics = { const totalMessagesInHour = new Map(); // total messages in hour 0, 1, ... 23 of weekday const days = to.diff(from, 'days') + 1; // total days - const summarize = (m) => ({ metrics, msgs }) => { - if (metrics && !metrics.chatDuration) { + const summarize = (m) => ({ metrics, msgs, onHold = false }) => { + if (metrics && !metrics.chatDuration && !onHold) { openConversations++; } totalMessages += msgs; @@ -306,7 +306,6 @@ export const Analytics = { lt: m.add(1, 'days'), }; const result = Promise.await(LivechatRooms.getAnalyticsBetweenDate(date, { departmentId }).toArray()); - console.log(result); totalConversations += result.length; result.forEach(summarize(clonedDate)); diff --git a/app/models/server/models/LivechatRooms.js b/app/models/server/models/LivechatRooms.js index e0cd513491198..dc73c211a2c13 100644 --- a/app/models/server/models/LivechatRooms.js +++ b/app/models/server/models/LivechatRooms.js @@ -579,7 +579,7 @@ export class LivechatRooms extends Base { servedBy: '$_id.servedBy', metrics: '$_id.metrics', msgs: '$messagesCount', - onHold: '$onHold', + onHold: '$_id.onHold', }, }, ]);