[NEW] Omnichannel source identification fields (#23090)

* Add new fields to IOmnichannelRoom and adapt livechat bridge to them

* Add source information to places that create livechat rooms

* Add deprecation warning to unused livechat methods and remove source from native facebook integration

* Remove unnecesary alias for widget

* Update app/lib/server/lib/deprecationWarningLogger.ts

* Update Apps-Engine version

* frontend part

* Change way of identifying when a chat is coming through widget

* Update deprecationlogger to new logger interface

* Fix usage of source.type as key

* sms icon

* [NEW] Add Channel Source details to room info panel (#23224)

* Add Source icon/text to room info

* Fix TS error and styling

* Change order

* Typing and style fix

* Use source.id instead of email object

* useEndpoint

* Revert "Merge branch 'develop' into new/omnichannel-source-fields"

This reverts commit 7fea2ad1fc, reversing
changes made to dbbcaf4601.

* Removing unnecesary changes from branch

* why github, why?

* Bump icons & fuselage to latest versions

Co-authored-by: Kevin Aleman <kevin.aleman@rocket.chat>
Co-authored-by: Tiago Evangelista Pinto <tiago.evangelista@rocket.chat>
Co-authored-by: Martin Schoeler <martin.schoeler@rocket.chat>
pull/23279/head
Douglas Gubert 5 years ago committed by GitHub
parent c2ab5e128c
commit 0f36b36ca4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 14
      app/api/server/helpers/deprecationWarning.js
  2. 15
      app/api/server/helpers/deprecationWarning.ts
  3. 13
      app/api/server/helpers/isWidget.ts
  4. 1
      app/api/server/index.js
  5. 17
      app/apps/server/bridges/livechat.ts
  6. 7
      app/lib/server/lib/deprecationWarningLogger.ts
  7. 5
      app/livechat/imports/server/rest/sms.js
  8. 2
      app/livechat/imports/server/rest/upload.js
  9. 11
      app/livechat/server/api/v1/message.js
  10. 10
      app/livechat/server/api/v1/room.js
  11. 11
      app/livechat/server/api/v1/videoCall.js
  12. 7
      app/livechat/server/lib/Helper.js
  13. 6
      app/livechat/server/methods/sendMessageLivechat.js
  14. 10
      app/livechat/server/methods/startFileUploadRoom.js
  15. 13
      app/livechat/server/methods/startVideoCall.js
  16. 6
      app/ui-sidenav/client/roomList.js
  17. 14
      client/hooks/useRoomIcon.tsx
  18. 8
      client/views/admin/emailInbox/EmailInboxForm.js
  19. 4
      client/views/omnichannel/components/Info.tsx
  20. 3
      client/views/omnichannel/directory/chats/contextualBar/ChatInfo.js
  21. 74
      client/views/omnichannel/directory/chats/contextualBar/SourceField.tsx
  22. 14
      client/views/omnichannel/directory/contacts/contextualBar/ContactNewEdit.js
  23. 23
      definition/IRoom.ts
  24. 90
      package-lock.json
  25. 8
      package.json
  26. 3
      packages/rocketchat-i18n/i18n/en.i18n.json
  27. 9264
      packages/rocketchat-i18n/i18n/es.i18n.json
  28. 6
      server/features/EmailInbox/EmailInbox_Incoming.ts
  29. 1
      server/modules/watchers/publishFields.ts

@ -1,14 +0,0 @@
import { API } from '../api';
API.helperMethods.set('deprecationWarning', function _deprecationWarning({ endpoint, versionWillBeRemoved, response }) {
const warningMessage = `The endpoint "${ endpoint }" is deprecated and will be removed after version ${ versionWillBeRemoved }`;
console.warn(warningMessage);
if (process.env.NODE_ENV === 'development') {
return {
warning: warningMessage,
...response,
};
}
return response;
});

@ -0,0 +1,15 @@
import { API } from '../api';
import { apiDeprecationLogger } from '../../../lib/server/lib/deprecationWarningLogger';
(API as any).helperMethods.set('deprecationWarning', function _deprecationWarning({ endpoint, versionWillBeRemoved, response }: { endpoint: string; versionWillBeRemoved: string; response: any }) {
const warningMessage = `The endpoint "${ endpoint }" is deprecated and will be removed after version ${ versionWillBeRemoved }`;
apiDeprecationLogger.warn(warningMessage);
if (process.env.NODE_ENV === 'development') {
return {
warning: warningMessage,
...response,
};
}
return response;
});

@ -0,0 +1,13 @@
import { parse } from 'cookie';
import { API } from '../api';
(API as any).helperMethods.set('isWidget', function _isWidget() {
// @ts-expect-error
const { headers } = this.request;
const { rc_room_type: roomType, rc_is_widget: isWidget } = parse(headers.cookie);
const isLivechatRoom = roomType && roomType === 'l';
return !!(isLivechatRoom && isWidget === 't');
});

@ -9,6 +9,7 @@ import './helpers/insertUserObject';
import './helpers/isUserFromParams';
import './helpers/parseJsonQuery';
import './helpers/requestParams';
import './helpers/isWidget';
import './default/info';
import './v1/assets';
import './v1/channels';

@ -19,6 +19,7 @@ import {
LivechatRooms,
} from '../../../models/server';
import { AppServerOrchestrator } from '../orchestrator';
import { OmnichannelSourceType } from '../../../../definition/IRoom';
export class AppLivechatBridge extends LivechatBridge {
// eslint-disable-next-line no-empty-function
@ -45,7 +46,13 @@ export class AppLivechatBridge extends LivechatBridge {
guest: this.orch.getConverters()?.get('visitors').convertAppVisitor(message.visitor),
message: this.orch.getConverters()?.get('messages').convertAppMessage(message),
agent: undefined,
roomInfo: undefined,
roomInfo: {
source: {
type: OmnichannelSourceType.APP,
id: appId,
alias: this.orch.getManager()?.getOneById(appId)?.getNameSlug(),
},
},
});
return msg._id;
@ -81,7 +88,13 @@ export class AppLivechatBridge extends LivechatBridge {
guest: this.orch.getConverters()?.get('visitors').convertAppVisitor(visitor),
agent: agentRoom,
rid: Random.id(),
roomInfo: undefined,
roomInfo: {
source: {
type: OmnichannelSourceType.APP,
id: appId,
alias: this.orch.getManager()?.getOneById(appId)?.getNameSlug(),
},
},
extraParams: undefined,
});

@ -0,0 +1,7 @@
import { Logger } from '../../../logger/server';
const deprecationLogger = new Logger('DeprecationWarning');
export const apiDeprecationLogger = deprecationLogger.section('API');
export const methodDeprecationLogger = deprecationLogger.section('METHOD');
export const functionDeprecationLogger = deprecationLogger.section('FUNCTION');

@ -7,6 +7,7 @@ import { LivechatRooms, LivechatVisitors, LivechatDepartment } from '../../../..
import { API } from '../../../../api/server';
import { SMS } from '../../../../sms';
import { Livechat } from '../../../server/lib/Livechat';
import { OmnichannelSourceType } from '../../../../../definition/IRoom';
const getUploadFile = (details, fileUrl) => {
const response = HTTP.get(fileUrl, { npmRequestOptions: { encoding: null } });
@ -83,6 +84,10 @@ API.v1.addRoute('livechat/sms-incoming/:service', {
sms: {
from: sms.to,
},
source: {
type: OmnichannelSourceType.SMS,
alias: this.urlParams.service,
},
},
};

@ -72,6 +72,6 @@ API.v1.addRoute('livechat/upload/:rid', {
uploadedFile.description = fields.description;
delete fields.description;
API.v1.success(Meteor.call('sendFileLivechatMessage', this.urlParams.rid, visitorToken, uploadedFile, fields));
return API.v1.success(Meteor.call('sendFileLivechatMessage', this.urlParams.rid, visitorToken, uploadedFile, fields));
},
});

@ -10,6 +10,7 @@ import { findGuest, findRoom, normalizeHttpHeaderData } from '../lib/livechat';
import { Livechat } from '../../lib/Livechat';
import { normalizeMessageFileUpload } from '../../../../utils/server/functions/normalizeMessageFileUpload';
import { settings } from '../../../../settings/server';
import { OmnichannelSourceType } from '../../../../../definition/IRoom';
API.v1.addRoute('livechat/message', {
post() {
@ -56,6 +57,11 @@ API.v1.addRoute('livechat/message', {
token,
},
agent,
roomInfo: {
source: {
type: this.isWidget() ? OmnichannelSourceType.WIDGET : OmnichannelSourceType.API,
},
},
};
const result = Promise.await(Livechat.sendMessage(sendMessage));
@ -305,6 +311,11 @@ API.v1.addRoute('livechat/messages', { authRequired: true }, {
token: visitorToken,
msg: message.msg,
},
roomInfo: {
source: {
type: this.isWidget() ? OmnichannelSourceType.WIDGET : OmnichannelSourceType.API,
},
},
};
const sentMessage = Promise.await(Livechat.sendMessage(sendMessage));
return {

@ -10,7 +10,7 @@ import { findGuest, findRoom, getRoom, settings, findAgent, onCheckRoomParams }
import { Livechat } from '../../lib/Livechat';
import { normalizeTransferredByData } from '../../lib/Helper';
import { findVisitorInfo } from '../lib/visitors';
import { OmnichannelSourceType } from '../../../../../definition/IRoom';
API.v1.addRoute('livechat/room', {
get() {
@ -46,7 +46,13 @@ API.v1.addRoute('livechat/room', {
}
const rid = Random.id();
room = Promise.await(getRoom({ guest, rid, agent, extraParams }));
const roomInfo = {
source: {
type: this.isWidget() ? OmnichannelSourceType.WIDGET : OmnichannelSourceType.API,
},
};
room = Promise.await(getRoom({ guest, rid, agent, roomInfo, extraParams }));
return API.v1.success(room);
}

@ -6,6 +6,7 @@ import { Messages } from '../../../../models';
import { settings as rcSettings } from '../../../../settings';
import { API } from '../../../../api/server';
import { findGuest, getRoom, settings } from '../lib/livechat';
import { OmnichannelSourceType } from '../../../../../definition/IRoom';
API.v1.addRoute('livechat/video.call/:token', {
get() {
@ -26,7 +27,13 @@ API.v1.addRoute('livechat/video.call/:token', {
}
const rid = this.queryParams.rid || Random.id();
const roomInfo = { jitsiTimeout: new Date(Date.now() + 3600 * 1000) };
const roomInfo = {
jitsiTimeout: new Date(Date.now() + 3600 * 1000),
source: {
type: OmnichannelSourceType.API,
alias: 'video-call',
},
};
const { room } = getRoom({ guest, rid, roomInfo });
const config = settings();
if (!config.theme || !config.theme.actionLinks) {
@ -50,7 +57,7 @@ API.v1.addRoute('livechat/video.call/:token', {
timeout: new Date(Date.now() + 3600 * 1000),
};
return API.v1.success({ videoCall });
return API.v1.success(this.deprecationWarning({ videoCall }));
} catch (e) {
return API.v1.failure(e);
}

@ -15,6 +15,7 @@ import notifications from '../../../notifications/server/lib/Notifications';
import { sendNotification } from '../../../lib/server';
import { sendMessage } from '../../../lib/server/functions/sendMessage';
import { queueInquiry, saveQueueInquiry } from './QueueManager';
import { OmnichannelSourceType } from '../../../../definition/IRoom';
const logger = new Logger('LivechatHelper');
const emailValidationRegex = /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
@ -60,6 +61,12 @@ export const createLivechatRoom = (rid, name, guest, roomInfo = {}, extraData =
cl: false,
open: true,
waitingResponse: true,
// this should be overriden by extraRoomInfo when provided
// in case it's not provided, we'll use this "default" type
source: {
type: OmnichannelSourceType.OTHER,
alias: 'unknown',
},
}, extraRoomInfo);
const roomId = Rooms.insert(room);

@ -3,6 +3,7 @@ import { Match, check } from 'meteor/check';
import { LivechatVisitors } from '../../../models';
import { Livechat } from '../lib/Livechat';
import { OmnichannelSourceType } from '../../../../definition/IRoom';
Meteor.methods({
sendMessageLivechat({ token, _id, rid, msg, file, attachments }, agent) {
@ -40,6 +41,11 @@ Meteor.methods({
attachments,
},
agent,
roomInfo: {
source: {
type: OmnichannelSourceType.API,
},
},
});
},
});

@ -3,9 +3,12 @@ import { Random } from 'meteor/random';
import { LivechatVisitors } from '../../../models';
import { Livechat } from '../lib/Livechat';
import { methodDeprecationLogger } from '../../../lib/server/lib/deprecationWarningLogger';
import { OmnichannelSourceType } from '../../../../definition/IRoom';
Meteor.methods({
'livechat:startFileUploadRoom'(roomId, token) {
methodDeprecationLogger.warn('livechat:startFileUploadRoom will be deprecated in future versions of Rocket.Chat');
const guest = LivechatVisitors.getVisitorByToken(token);
const message = {
@ -16,6 +19,11 @@ Meteor.methods({
token: guest.token,
};
return Livechat.getRoom(guest, message);
const roomInfo = {
source: OmnichannelSourceType.API,
alias: 'file-upload',
};
return Livechat.getRoom(guest, message, roomInfo);
},
});

@ -4,9 +4,12 @@ import { Random } from 'meteor/random';
import { Messages } from '../../../models';
import { settings } from '../../../settings';
import { Livechat } from '../lib/Livechat';
import { methodDeprecationLogger } from '../../../lib/server/lib/deprecationWarningLogger';
import { OmnichannelSourceType } from '../../../../definition/IRoom';
Meteor.methods({
async 'livechat:startVideoCall'(roomId) {
methodDeprecationLogger.warn('livechat:startVideoCall will be deprecated in future versions of Rocket.Chat');
if (!Meteor.userId()) {
throw new Meteor.Error('error-not-authorized', 'Not authorized', { method: 'livechat:closeByVisitor' });
}
@ -20,7 +23,15 @@ Meteor.methods({
ts: new Date(),
};
const room = await Livechat.getRoom(guest, message, { jitsiTimeout: new Date(Date.now() + 3600 * 1000) });
const roomInfo = {
jitsiTimeout: new Date(Date.now() + 3600 * 1000),
source: {
type: OmnichannelSourceType.API,
alias: 'video-call',
},
};
const room = await Livechat.getRoom(guest, message, roomInfo);
message.rid = room._id;
Messages.createWithTypeRoomIdMessageAndUser('livechat_video_call', room._id, '', guest, {

@ -170,6 +170,7 @@ const mergeSubRoom = (subscription) => {
priorityId: 1,
livechatData: 1,
departmentId: 1,
source: 1,
},
};
@ -208,6 +209,7 @@ const mergeSubRoom = (subscription) => {
livechatData,
departmentId,
ts,
source,
} = room;
subscription.lm = subscription.lr ? new Date(Math.max(subscription.lr, lastRoomUpdate)) : lastRoomUpdate;
@ -243,6 +245,7 @@ const mergeSubRoom = (subscription) => {
livechatData,
departmentId,
ts,
source,
});
};
@ -283,7 +286,7 @@ const mergeRoomSub = (room) => {
livechatData,
departmentId,
ts,
source,
} = room;
Subscriptions.update({
@ -319,6 +322,7 @@ const mergeRoomSub = (room) => {
departmentId,
jitsiTimeout,
ts,
source,
...getLowerCaseNames(room, sub.name, sub.fname),
},
});

@ -25,8 +25,20 @@ export const useRoomIcon = (room: IRoom): ReactNode | { name: string; color?: st
case 'c':
return { name: 'hash' };
case 'l':
const omnichannelRoom = room as IOmnichannelRoom;
const icon =
{
widget: 'livechat',
email: 'mail',
sms: 'sms',
app: 'headset', // TODO: use app icon
api: 'headset', // TODO: use api icon
other: 'headset',
}[omnichannelRoom.source?.type as string] || 'headset';
return {
name: 'headset',
name: icon,
color: colors[(room as unknown as IOmnichannelRoom)?.v.status || 'offline'],
};
case 'd':

@ -19,10 +19,10 @@ import GenericModal from '../../../components/GenericModal';
import Page from '../../../components/Page';
import { useSetModal } from '../../../contexts/ModalContext';
import { useRoute } from '../../../contexts/RouterContext';
import { useEndpoint } from '../../../contexts/ServerContext';
import { useToastMessageDispatch } from '../../../contexts/ToastMessagesContext';
import { useTranslation } from '../../../contexts/TranslationContext';
import { useComponentDidUpdate } from '../../../hooks/useComponentDidUpdate';
import { useEndpointAction } from '../../../hooks/useEndpointAction';
import { useForm } from '../../../hooks/useForm';
const initialValues = {
@ -127,9 +127,9 @@ function EmailInboxForm({ id, data }) {
const close = useCallback(() => router.push({}), [router]);
const saveEmailInbox = useEndpointAction('POST', 'email-inbox');
const deleteAction = useEndpointAction('DELETE', `email-inbox/${id}`);
const emailAlreadyExistsAction = useEndpointAction('GET', `email-inbox.search?email=${email}`);
const saveEmailInbox = useEndpoint('POST', 'email-inbox');
const deleteAction = useEndpoint('DELETE', `email-inbox/${id}`);
const emailAlreadyExistsAction = useEndpoint('GET', `email-inbox.search?email=${email}`);
useComponentDidUpdate(() => {
setEmailError(!isEmail(email) ? t('Validate_email_address') : null);

@ -1,5 +1,5 @@
import { css } from '@rocket.chat/css-in-js';
import React from 'react';
import React, { FC } from 'react';
import UserCard from '../../../components/UserCard';
@ -7,7 +7,7 @@ const wordBreak = css`
word-break: break-word;
`;
const Info = ({ className, ...props }) => (
const Info: FC<{ className?: string }> = ({ className, ...props }) => (
<UserCard.Info className={[className, wordBreak]} flexShrink={0} {...props} />
);

@ -22,6 +22,7 @@ import AgentField from './AgentField';
import ContactField from './ContactField';
import DepartmentField from './DepartmentField';
import PriorityField from './PriorityField';
import SourceField from './SourceField';
import VisitorClientInfo from './VisitorClientInfo';
function ChatInfo({ id, route }) {
@ -48,6 +49,7 @@ function ChatInfo({ id, route }) {
responseBy,
priorityId,
livechatData,
source,
} = room || { room: { v: {} } };
const routePath = useRoute(route || 'omnichannel-directory');
@ -99,6 +101,7 @@ function ChatInfo({ id, route }) {
<>
<VerticalBar.ScrollableContent p='x24'>
<Margins block='x4'>
{source && <SourceField room={room} />}
{room && v && <ContactField contact={v} room={room} />}
{visitorId && <VisitorClientInfo uid={visitorId} />}
{servedBy && <AgentField agent={servedBy} />}

@ -0,0 +1,74 @@
import { Icon, Box } from '@rocket.chat/fuselage';
import React, { FC } from 'react';
import { IOmnichannelRoom } from '../../../../../../definition/IRoom';
import { useTranslation } from '../../../../../contexts/TranslationContext';
import { useRoomIcon } from '../../../../../hooks/useRoomIcon';
import Field from '../../../components/Field';
import Info from '../../../components/Info';
import Label from '../../../components/Label';
type SourceFieldProps = {
room: IOmnichannelRoom;
};
const SourceField: FC<SourceFieldProps> = ({ room }) => {
const t = useTranslation();
const roomSource = room.source.alias || room.source.id || room.source.type;
// TODO: create a hook that gets the default types values (alias, icons, ids, etc...)
// so we don't have to write this object again and again
const defaultTypesLabels: {
widget: string;
email: string;
sms: string;
app: string;
api: string;
other: string;
} = {
widget: t('Livechat'),
email: t('Email'),
sms: t('SMS'),
app: t('Custom_Integration'), // TODO: use app text
api: t('Custom_Integration'), // TODO: use app text
other: t('Custom_Integration'),
};
const defaultTypesVisitorData: {
widget: string | undefined;
email: string | undefined;
sms: string;
app: string;
api: string;
other: string;
} = {
widget: '',
email: room?.source.id,
sms: t('External'),
app: t('External'), // TODO: use app text
api: t('External'),
other: t('External'),
};
const sourceIcon = useRoomIcon(room) as { name: string; color?: string | undefined };
const sourceName = sourceIcon?.name || '';
return (
<Field>
<Label>{t('Channel')}</Label>
<Info>
<Box display='flex' alignItems='center'>
<Icon name={sourceName} size='x24' />
<Label mi='x8' mbe='0'>
{defaultTypesLabels[room.source.type] || roomSource}
</Label>
{defaultTypesVisitorData[room.source.type]}
</Box>
</Info>
</Field>
);
};
export default SourceField;

@ -8,11 +8,11 @@ import { isEmail } from '../../../../../../app/utils/client';
import CustomFieldsForm from '../../../../../components/CustomFieldsForm';
import VerticalBar from '../../../../../components/VerticalBar';
import { createToken } from '../../../../../components/helpers';
import { useEndpoint } from '../../../../../contexts/ServerContext';
import { useToastMessageDispatch } from '../../../../../contexts/ToastMessagesContext';
import { useTranslation } from '../../../../../contexts/TranslationContext';
import { AsyncStatePhase } from '../../../../../hooks/useAsyncState';
import { useComponentDidUpdate } from '../../../../../hooks/useComponentDidUpdate';
import { useEndpointAction } from '../../../../../hooks/useEndpointAction';
import { useEndpointData } from '../../../../../hooks/useEndpointData';
import { useForm } from '../../../../../hooks/useForm';
import { formsSubscription } from '../../../additionalForms';
@ -107,9 +107,15 @@ function ContactNewEdit({ id, data, close }) {
[allCustomFields],
);
const saveContact = useEndpoint('POST', 'omnichannel/contact');
const emailAlreadyExistsAction = useEndpoint('GET', `omnichannel/contact.search?email=${email}`);
const phoneAlreadyExistsAction = useEndpoint('GET', `omnichannel/contact.search?phone=${phone}`);
const saveContact = useEndpointAction('POST', 'omnichannel/contact');
const emailAlreadyExistsAction = useEndpointAction(
'GET',
`omnichannel/contact.search?email=${email}`,
);
const phoneAlreadyExistsAction = useEndpointAction(
'GET',
`omnichannel/contact.search?phone=${phone}`,
);
const checkEmailExists = useMutableCallback(async () => {
if (!isEmail(email)) {

@ -73,6 +73,14 @@ export interface IDirectMessageRoom extends Omit<IRoom, 'default' | 'featured' |
usernames: Array<Username>;
}
export enum OmnichannelSourceType {
WIDGET = 'widget',
EMAIL = 'email',
SMS = 'sms',
APP = 'app',
API = 'api',
OTHER = 'other', // catch-all source type
}
export interface IOmnichannelRoom extends Omit<IRoom, 'default' | 'featured' | 'broadcast' | 'featured' | ''> {
t: 'l';
@ -81,6 +89,21 @@ export interface IOmnichannelRoom extends Omit<IRoom, 'default' | 'featured' | '
token?: string;
status: 'online' | 'busy' | 'away' | 'offline';
};
email?: {
// Data used when the room is created from an email, via email Integration.
inbox: string;
thread: string;
replyTo: string;
subject: string;
};
source: {
// The source, or client, which created the Omnichannel room
type: OmnichannelSourceType;
// An optional identification of external sources, such as an App
id?: string;
// A human readable alias that goes with the ID, for post analytical purposes
alias?: string;
};
transcriptRequest?: IRequestTranscript;
servedBy?: {
_id: string;

90
package-lock.json generated

@ -5337,16 +5337,66 @@
}
},
"@rocket.chat/fuselage": {
"version": "0.6.3-dev.322",
"resolved": "https://registry.npmjs.org/@rocket.chat/fuselage/-/fuselage-0.6.3-dev.322.tgz",
"integrity": "sha512-+0zDTEfSuPDZuwq6T/oxC5klWyEO25U3FgfEDzWIDQpKk74LAMy2ULawQd1O37r7emvg8SPvxy7S9vyQNHnGsg==",
"version": "0.6.3-dev.326",
"resolved": "https://registry.npmjs.org/@rocket.chat/fuselage/-/fuselage-0.6.3-dev.326.tgz",
"integrity": "sha512-t4jEM4kHGjfXgZ5uxickjjUFxJR0G8OIQVadVeX4CdlCX4YtqFbNWEoBvgF1gRCicJFvlJqIADiHtZKGMpZ/kA==",
"requires": {
"@rocket.chat/css-in-js": "^0.6.3-dev.322+b067cee6",
"@rocket.chat/css-supports": "^0.6.3-dev.322+b067cee6",
"@rocket.chat/fuselage-tokens": "^0.6.3-dev.322+b067cee6",
"@rocket.chat/memo": "^0.6.3-dev.322+b067cee6",
"@rocket.chat/css-in-js": "^0.6.3-dev.326+35894d44",
"@rocket.chat/css-supports": "^0.6.3-dev.326+35894d44",
"@rocket.chat/fuselage-tokens": "^0.6.3-dev.326+35894d44",
"@rocket.chat/memo": "^0.6.3-dev.326+35894d44",
"invariant": "^2.2.4",
"react-keyed-flatten-children": "^1.3.0"
},
"dependencies": {
"@rocket.chat/css-in-js": {
"version": "0.6.3-dev.326",
"resolved": "https://registry.npmjs.org/@rocket.chat/css-in-js/-/css-in-js-0.6.3-dev.326.tgz",
"integrity": "sha512-JPsMfWhm87CmCUVGWgICfjoH2egAZSqqoMNdWNRgWm7H367wzcP51uLu2YF3HMEPa1la3uDE7GNPX1RzQ4TI6w==",
"requires": {
"@emotion/hash": "^0.8.0",
"@rocket.chat/css-supports": "^0.6.3-dev.326+35894d44",
"@rocket.chat/memo": "^0.6.3-dev.326+35894d44",
"@rocket.chat/stylis-logical-props-middleware": "^0.6.3-dev.326+35894d44",
"stylis": "^4.0.10"
}
},
"@rocket.chat/css-supports": {
"version": "0.6.3-dev.326",
"resolved": "https://registry.npmjs.org/@rocket.chat/css-supports/-/css-supports-0.6.3-dev.326.tgz",
"integrity": "sha512-NzTRiGhOadcQr0iHxLzFWy0K9y8+TMxG21IwGEQt+3FPGxfnhGDNkqyWSSwVuMG7xmRZgl/s7iAYAEUlmc06dg==",
"requires": {
"@rocket.chat/memo": "^0.6.3-dev.326+35894d44",
"tslib": "^2.3.1"
}
},
"@rocket.chat/fuselage-tokens": {
"version": "0.6.3-dev.326",
"resolved": "https://registry.npmjs.org/@rocket.chat/fuselage-tokens/-/fuselage-tokens-0.6.3-dev.326.tgz",
"integrity": "sha512-ORltLhsMzifKKz6SCyCwKNx7wXXAkkw2B+wumgpa/nvOXiYiI5gOp4M/04sVvjVIAHo9+gd1LqB1im1LQiQ8TA=="
},
"@rocket.chat/memo": {
"version": "0.6.3-dev.326",
"resolved": "https://registry.npmjs.org/@rocket.chat/memo/-/memo-0.6.3-dev.326.tgz",
"integrity": "sha512-Mqtk+fNoSB6vjqdQcc8dNlP+E46D6AlVVGYs02+KRomRm5I3Bjto9ZfwVdHPBEopHY04OSyRmDroMGdwxxj2ww==",
"requires": {
"tslib": "^2.3.0"
}
},
"@rocket.chat/stylis-logical-props-middleware": {
"version": "0.6.3-dev.326",
"resolved": "https://registry.npmjs.org/@rocket.chat/stylis-logical-props-middleware/-/stylis-logical-props-middleware-0.6.3-dev.326.tgz",
"integrity": "sha512-1k0UjTnMKuyCOTzE2bCrssFY64YXHD5hc8rEMIGxlfJ4O70Q8dGV30kg2pKm4yhXHvUnBg3cxtT98nqvN7kBQg==",
"requires": {
"@rocket.chat/css-supports": "^0.6.3-dev.326+35894d44",
"tslib": "^2.2.0"
}
},
"tslib": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
"integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw=="
}
}
},
"@rocket.chat/fuselage-hooks": {
@ -5378,9 +5428,9 @@
"integrity": "sha512-CVB0IRtpmc94fjQsMEIg6TkC2KX4WXBQ1ZZrOxgmuIcj4HQG/gBVah0B1O3ApQvORDijtJxogGE1oTXoLXrf0A=="
},
"@rocket.chat/icons": {
"version": "0.6.3-dev.322",
"resolved": "https://registry.npmjs.org/@rocket.chat/icons/-/icons-0.6.3-dev.322.tgz",
"integrity": "sha512-Ew5dIfoOovi/2cZxUboAD6jIr5dsPEwGDKBOxp9qVdP5VeJ+xzniLYK7XGh+4Lv98QIeT3Toi6en/RPcz9c9+g=="
"version": "0.6.3-dev.327",
"resolved": "https://registry.npmjs.org/@rocket.chat/icons/-/icons-0.6.3-dev.327.tgz",
"integrity": "sha512-oRazxPrfVP4WPDE4Cs7UCjLsKzUdagKVeQf1f0DbUtQAQRWHEofnzDjakYFtkli/e4Ak1JN9Bcqeq4ejFoU7wQ=="
},
"@rocket.chat/livechat": {
"version": "1.9.5",
@ -10960,6 +11010,11 @@
"@types/node": "*"
}
},
"@types/cookie": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz",
"integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q=="
},
"@types/dompurify": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/@types/dompurify/-/dompurify-2.2.2.tgz",
@ -17309,6 +17364,11 @@
"safe-buffer": "~5.1.1"
}
},
"cookie": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz",
"integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA=="
},
"cookie-signature": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
@ -17957,7 +18017,6 @@
"version": "2.4.7",
"resolved": "https://registry.npmjs.org/css-vars-ponyfill/-/css-vars-ponyfill-2.4.7.tgz",
"integrity": "sha512-KhG3AbiZrUpIvAQ9Oc/iBqCitmXg6MajFqNRQd9nHvlwOo8p54HTq5DFCIaAUwMGRyttJ+mBmZCRSHJpe6J9cg==",
"dev": true,
"requires": {
"balanced-match": "^1.0.2",
"get-css-data": "^2.0.2"
@ -17966,8 +18025,7 @@
"balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
"dev": true
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
}
}
},
@ -18319,8 +18377,7 @@
"date-fns": {
"version": "2.24.0",
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.24.0.tgz",
"integrity": "sha512-6ujwvwgPID6zbI0o7UbURi2vlLDR9uP26+tW6Lg+Ji3w7dd0i3DOcjcClLjLPranT60SSEFBwdSyYwn/ZkPIuw==",
"dev": true
"integrity": "sha512-6ujwvwgPID6zbI0o7UbURi2vlLDR9uP26+tW6Lg+Ji3w7dd0i3DOcjcClLjLPranT60SSEFBwdSyYwn/ZkPIuw=="
},
"date.js": {
"version": "0.3.3",
@ -22654,8 +22711,7 @@
"get-css-data": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/get-css-data/-/get-css-data-2.0.2.tgz",
"integrity": "sha512-pYqg80/7u/MdBrrAQj2OIoZ08TxEnvCHyU5WFnPxxS/D0S8OpUTkqGFRzn8bO38DmtCuYBpR9VMCen78BL4jiQ==",
"dev": true
"integrity": "sha512-pYqg80/7u/MdBrrAQj2OIoZ08TxEnvCHyU5WFnPxxS/D0S8OpUTkqGFRzn8bO38DmtCuYBpR9VMCen78BL4jiQ=="
},
"get-func-name": {
"version": "2.0.0",

@ -162,18 +162,19 @@
"@rocket.chat/apps-engine": "^1.28.0-alpha.5428",
"@rocket.chat/css-in-js": "^0.6.3-dev.322",
"@rocket.chat/emitter": "^0.6.3-dev.322",
"@rocket.chat/fuselage": "^0.6.3-dev.322",
"@rocket.chat/fuselage": "^0.6.3-dev.326",
"@rocket.chat/fuselage-hooks": "^0.6.3-dev.322",
"@rocket.chat/fuselage-polyfills": "^0.6.3-dev.322",
"@rocket.chat/fuselage-tokens": "^0.6.3-dev.322",
"@rocket.chat/fuselage-ui-kit": "^0.6.3-dev.322",
"@rocket.chat/icons": "^0.6.3-dev.322",
"@rocket.chat/icons": "^0.6.3-dev.327",
"@rocket.chat/memo": "^0.6.3-dev.322",
"@rocket.chat/message-parser": "^0.6.3-dev.326",
"@rocket.chat/mp3-encoder": "^0.24.0",
"@rocket.chat/string-helpers": "^0.6.3-dev.322",
"@rocket.chat/ui-kit": "^0.6.3-dev.322",
"@slack/client": "^4.12.0",
"@types/cookie": "^0.4.1",
"@types/lodash": "^4.14.171",
"adm-zip": "0.4.14",
"agenda": "github:RocketChat/agenda#3.1.2",
@ -196,8 +197,11 @@
"codemirror": "^5.62.0",
"colorette": "^1.3.0",
"connect": "^3.7.0",
"cookie": "^0.4.1",
"cors": "^2.8.5",
"css-vars-ponyfill": "^2.4.7",
"csv-parse": "^4.16.3",
"date-fns": "^2.23.0",
"dompurify": "^2.2.9",
"ejson": "^2.2.1",
"emailreplyparser": "^0.0.5",

@ -1292,6 +1292,7 @@
"Custom_Fields": "Custom Fields",
"Custom_Field_Removed": "Custom Field Removed",
"Custom_Field_Not_Found": "Custom Field not found",
"Custom_Integration": "Custom Integration",
"Custom_oauth_helper": "When setting up your OAuth Provider, you'll have to inform a Callback URL. Use <pre>%s</pre> .",
"Custom_oauth_unique_name": "Custom oauth unique name",
"Custom_Script_Logged_In": "Custom Script for Logged In Users",
@ -1812,6 +1813,7 @@
"Export_My_Data": "Export My Data (JSON)",
"expression": "Expression",
"Extended": "Extended",
"External": "External",
"External_Domains": "External Domains",
"External_Queue_Service_URL": "External Queue Service URL",
"External_Service": "External Service",
@ -3885,6 +3887,7 @@
"Smarsh_MissingEmail_Email_Description": "The email to show for a user account when their email address is missing, generally happens with bot accounts.",
"Smarsh_Timezone": "Smarsh Timezone",
"Smileys_and_People": "Smileys & People",
"SMS": "SMS",
"SMS_Default_Omnichannel_Department": "Omnichannel Department (Default)",
"SMS_Default_Omnichannel_Department_Description": "If set, all new incoming chats initiated by this integration will be routed to this department.",
"SMS_Enabled": "SMS Enabled",

File diff suppressed because it is too large Load Diff

@ -9,6 +9,7 @@ import { LivechatRooms, LivechatVisitors, Messages } from '../../../app/models/s
import { FileUpload } from '../../../app/file-upload/server';
import { QueueManager } from '../../../app/livechat/server/lib/QueueManager';
import { settings } from '../../../app/settings/server';
import { OmnichannelSourceType } from '../../../definition/IRoom';
type FileAttachment = {
title: string;
@ -171,6 +172,11 @@ export async function onEmailReceived(email: ParsedMail, inbox: string, departme
replyTo: email.from.value[0].address,
subject: email.subject,
},
source: {
type: OmnichannelSourceType.EMAIL,
id: inbox,
alias: 'email-inbox',
},
},
agent: undefined,
}).then(async () => {

@ -94,6 +94,7 @@ export const roomFields = {
v: 1,
departmentId: 1,
servedBy: 1,
source: 1,
transcriptRequest: 1,
onHold: 1,
metrics: 1,

Loading…
Cancel
Save