Restructure omni services and add Chatwoot research snapshot
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
export const CHATWOOT_SET_USER = 'CHATWOOT_SET_USER';
|
||||
export const CHATWOOT_RESET = 'CHATWOOT_RESET';
|
||||
|
||||
export const ANALYTICS_IDENTITY = 'ANALYTICS_IDENTITY';
|
||||
export const ANALYTICS_RESET = 'ANALYTICS_RESET';
|
||||
@@ -0,0 +1,77 @@
|
||||
export const DEFAULT_MESSAGE_CREATED_CONDITION = [
|
||||
{
|
||||
attribute_key: 'message_type',
|
||||
filter_operator: 'equal_to',
|
||||
values: '',
|
||||
query_operator: 'and',
|
||||
custom_attribute_type: '',
|
||||
},
|
||||
];
|
||||
|
||||
export const DEFAULT_CONVERSATION_CONDITION = [
|
||||
{
|
||||
attribute_key: 'browser_language',
|
||||
filter_operator: 'equal_to',
|
||||
values: '',
|
||||
query_operator: 'and',
|
||||
custom_attribute_type: '',
|
||||
},
|
||||
];
|
||||
|
||||
export const DEFAULT_OTHER_CONDITION = [
|
||||
{
|
||||
attribute_key: 'status',
|
||||
filter_operator: 'equal_to',
|
||||
values: '',
|
||||
query_operator: 'and',
|
||||
custom_attribute_type: '',
|
||||
},
|
||||
];
|
||||
|
||||
export const DEFAULT_ACTIONS = [
|
||||
{
|
||||
action_name: 'assign_agent',
|
||||
action_params: [],
|
||||
},
|
||||
];
|
||||
|
||||
export const MESSAGE_CONDITION_VALUES = [
|
||||
{
|
||||
id: 'incoming',
|
||||
name: 'Incoming',
|
||||
i18nKey: 'INCOMING',
|
||||
},
|
||||
{
|
||||
id: 'outgoing',
|
||||
name: 'Outgoing',
|
||||
i18nKey: 'OUTGOING',
|
||||
},
|
||||
];
|
||||
|
||||
export const PRIORITY_CONDITION_VALUES = [
|
||||
{
|
||||
id: 'nil',
|
||||
name: 'None',
|
||||
i18nKey: 'NONE',
|
||||
},
|
||||
{
|
||||
id: 'low',
|
||||
name: 'Low',
|
||||
i18nKey: 'LOW',
|
||||
},
|
||||
{
|
||||
id: 'medium',
|
||||
name: 'Medium',
|
||||
i18nKey: 'MEDIUM',
|
||||
},
|
||||
{
|
||||
id: 'high',
|
||||
name: 'High',
|
||||
i18nKey: 'HIGH',
|
||||
},
|
||||
{
|
||||
id: 'urgent',
|
||||
name: 'Urgent',
|
||||
i18nKey: 'URGENT',
|
||||
},
|
||||
];
|
||||
288
research/chatwoot/app/javascript/dashboard/constants/editor.js
Normal file
288
research/chatwoot/app/javascript/dashboard/constants/editor.js
Normal file
@@ -0,0 +1,288 @@
|
||||
// Formatting rules for different contexts (channels and special contexts)
|
||||
// marks: inline formatting (strong, em, code, link, strike)
|
||||
// nodes: block structures (bulletList, orderedList, codeBlock, blockquote)
|
||||
export const FORMATTING = {
|
||||
// Channel formatting
|
||||
'Channel::Email': {
|
||||
marks: ['strong', 'em', 'code', 'link'],
|
||||
nodes: ['bulletList', 'orderedList', 'codeBlock', 'blockquote', 'image'],
|
||||
menu: [
|
||||
'copilot',
|
||||
'strong',
|
||||
'em',
|
||||
'code',
|
||||
'link',
|
||||
'bulletList',
|
||||
'orderedList',
|
||||
'undo',
|
||||
'redo',
|
||||
],
|
||||
},
|
||||
'Channel::WebWidget': {
|
||||
marks: ['strong', 'em', 'code', 'link', 'strike'],
|
||||
nodes: ['bulletList', 'orderedList', 'codeBlock', 'blockquote', 'image'],
|
||||
menu: [
|
||||
'copilot',
|
||||
'strong',
|
||||
'em',
|
||||
'code',
|
||||
'link',
|
||||
'strike',
|
||||
'bulletList',
|
||||
'orderedList',
|
||||
'undo',
|
||||
'redo',
|
||||
],
|
||||
},
|
||||
'Channel::Api': {
|
||||
marks: ['strong', 'em'],
|
||||
nodes: [],
|
||||
menu: ['copilot', 'strong', 'em', 'undo', 'redo'],
|
||||
},
|
||||
'Channel::FacebookPage': {
|
||||
marks: ['strong', 'em', 'code', 'strike'],
|
||||
nodes: ['bulletList', 'orderedList', 'codeBlock'],
|
||||
menu: [
|
||||
'copilot',
|
||||
'strong',
|
||||
'em',
|
||||
'code',
|
||||
'strike',
|
||||
'bulletList',
|
||||
'orderedList',
|
||||
'undo',
|
||||
'redo',
|
||||
],
|
||||
},
|
||||
'Channel::TwitterProfile': {
|
||||
marks: [],
|
||||
nodes: [],
|
||||
menu: [],
|
||||
},
|
||||
'Channel::TwilioSms': {
|
||||
marks: [],
|
||||
nodes: [],
|
||||
menu: [],
|
||||
},
|
||||
'Channel::Sms': {
|
||||
marks: [],
|
||||
nodes: [],
|
||||
menu: [],
|
||||
},
|
||||
'Channel::Whatsapp': {
|
||||
marks: ['strong', 'em', 'code', 'strike'],
|
||||
nodes: ['bulletList', 'orderedList', 'codeBlock'],
|
||||
menu: [
|
||||
'copilot',
|
||||
'strong',
|
||||
'em',
|
||||
'code',
|
||||
'strike',
|
||||
'bulletList',
|
||||
'orderedList',
|
||||
'undo',
|
||||
'redo',
|
||||
],
|
||||
},
|
||||
'Channel::Line': {
|
||||
marks: ['strong', 'em', 'code', 'strike'],
|
||||
nodes: ['codeBlock'],
|
||||
menu: ['copilot', 'strong', 'em', 'code', 'strike', 'undo', 'redo'],
|
||||
},
|
||||
'Channel::Telegram': {
|
||||
marks: ['strong', 'em', 'link', 'code'],
|
||||
nodes: [],
|
||||
menu: ['copilot', 'strong', 'em', 'link', 'code', 'undo', 'redo'],
|
||||
},
|
||||
'Channel::Instagram': {
|
||||
marks: ['strong', 'em', 'code', 'strike'],
|
||||
nodes: ['bulletList', 'orderedList'],
|
||||
menu: [
|
||||
'copilot',
|
||||
'strong',
|
||||
'em',
|
||||
'code',
|
||||
'bulletList',
|
||||
'orderedList',
|
||||
'strike',
|
||||
'undo',
|
||||
'redo',
|
||||
],
|
||||
},
|
||||
'Channel::Voice': {
|
||||
marks: [],
|
||||
nodes: [],
|
||||
menu: [],
|
||||
},
|
||||
'Channel::Tiktok': {
|
||||
marks: [],
|
||||
nodes: [],
|
||||
menu: [],
|
||||
},
|
||||
// Special contexts (not actual channels)
|
||||
'Context::PrivateNote': {
|
||||
marks: ['strong', 'em', 'code', 'link', 'strike'],
|
||||
nodes: ['bulletList', 'orderedList', 'codeBlock', 'blockquote'],
|
||||
menu: [
|
||||
'copilot',
|
||||
'strong',
|
||||
'em',
|
||||
'code',
|
||||
'link',
|
||||
'strike',
|
||||
'bulletList',
|
||||
'orderedList',
|
||||
'undo',
|
||||
'redo',
|
||||
],
|
||||
},
|
||||
'Context::Default': {
|
||||
marks: ['strong', 'em', 'code', 'link', 'strike'],
|
||||
nodes: ['bulletList', 'orderedList', 'codeBlock', 'blockquote'],
|
||||
menu: [
|
||||
'strong',
|
||||
'em',
|
||||
'code',
|
||||
'link',
|
||||
'strike',
|
||||
'bulletList',
|
||||
'orderedList',
|
||||
'undo',
|
||||
'redo',
|
||||
],
|
||||
},
|
||||
'Context::MessageSignature': {
|
||||
marks: ['strong', 'em', 'link'],
|
||||
nodes: ['image'],
|
||||
menu: ['strong', 'em', 'link', 'undo', 'redo', 'imageUpload'],
|
||||
},
|
||||
'Context::InboxSettings': {
|
||||
marks: ['strong', 'em', 'link'],
|
||||
nodes: [],
|
||||
menu: ['strong', 'em', 'link', 'undo', 'redo'],
|
||||
},
|
||||
'Context::Plain': {
|
||||
marks: [],
|
||||
nodes: [],
|
||||
menu: [],
|
||||
},
|
||||
};
|
||||
|
||||
// Editor menu options for Full Editor
|
||||
export const ARTICLE_EDITOR_MENU_OPTIONS = [
|
||||
'strong',
|
||||
'em',
|
||||
'link',
|
||||
'undo',
|
||||
'redo',
|
||||
'bulletList',
|
||||
'orderedList',
|
||||
'h1',
|
||||
'h2',
|
||||
'h3',
|
||||
'imageUpload',
|
||||
'code',
|
||||
];
|
||||
|
||||
/**
|
||||
* Markdown formatting patterns for stripping unsupported formatting.
|
||||
*
|
||||
* Maps camelCase type names to ProseMirror snake_case schema names.
|
||||
* Order matters: codeBlock before code to avoid partial matches.
|
||||
*/
|
||||
export const MARKDOWN_PATTERNS = [
|
||||
// --- BLOCK NODES ---
|
||||
{
|
||||
type: 'codeBlock', // PM: code_block, eg: ```js\ncode\n```
|
||||
patterns: [
|
||||
{ pattern: /`{3}(?:\w+)?\n?([\s\S]*?)`{3}/g, replacement: '$1' },
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'blockquote', // PM: blockquote, eg: > quote
|
||||
patterns: [{ pattern: /^> ?/gm, replacement: '' }],
|
||||
},
|
||||
{
|
||||
type: 'bulletList', // PM: bullet_list, eg: - item
|
||||
patterns: [{ pattern: /^[\t ]*[-*+]\s+/gm, replacement: '' }],
|
||||
},
|
||||
{
|
||||
type: 'orderedList', // PM: ordered_list, eg: 1. item
|
||||
patterns: [{ pattern: /^[\t ]*\d+\.\s+/gm, replacement: '' }],
|
||||
},
|
||||
{
|
||||
type: 'heading', // PM: heading, eg: ## Heading
|
||||
patterns: [{ pattern: /^#{1,6}\s+/gm, replacement: '' }],
|
||||
},
|
||||
{
|
||||
type: 'horizontalRule', // PM: horizontal_rule, eg: ---
|
||||
patterns: [{ pattern: /^(?:---|___|\*\*\*)\s*$/gm, replacement: '' }],
|
||||
},
|
||||
{
|
||||
type: 'image', // PM: image, eg: 
|
||||
patterns: [{ pattern: /!\[([^\]]*)\]\([^)]+\)/g, replacement: '$1' }],
|
||||
},
|
||||
{
|
||||
type: 'hardBreak', // PM: hard_break, eg: line\\\n or line \n
|
||||
patterns: [
|
||||
{ pattern: /\\\n/g, replacement: '\n' },
|
||||
{ pattern: / {2,}\n/g, replacement: '\n' },
|
||||
],
|
||||
},
|
||||
// --- INLINE MARKS ---
|
||||
{
|
||||
type: 'strong', // PM: strong, eg: **bold** or __bold__
|
||||
patterns: [
|
||||
{ pattern: /\*\*(.+?)\*\*/g, replacement: '$1' },
|
||||
{ pattern: /__(.+?)__/g, replacement: '$1' },
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'em', // PM: em, eg: *italic* or _italic_
|
||||
patterns: [
|
||||
{ pattern: /(?<!\*)\*(?!\*)(.+?)(?<!\*)\*(?!\*)/g, replacement: '$1' },
|
||||
// Match _text_ only at word boundaries (whitespace/string start/end)
|
||||
// Preserves underscores in URLs (e.g., https://example.com/path_name) and variable names
|
||||
{
|
||||
pattern: /(?<=^|[\s])_([^_\s][^_]*[^_\s]|[^_\s])_(?=$|[\s])/g,
|
||||
replacement: '$1',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'strike', // PM: strike, eg: ~~strikethrough~~
|
||||
patterns: [{ pattern: /~~(.+?)~~/g, replacement: '$1' }],
|
||||
},
|
||||
{
|
||||
type: 'code', // PM: code, eg: `inline code`
|
||||
patterns: [{ pattern: /`([^`]+)`/g, replacement: '$1' }],
|
||||
},
|
||||
{
|
||||
type: 'link', // PM: link
|
||||
patterns: [
|
||||
{ pattern: /\[([^\]]+)\]\([^)]+\)/g, replacement: '$1' }, // [text](url) -> text
|
||||
{ pattern: /<([a-zA-Z][a-zA-Z0-9+.-]*:[^\s>]+)>/g, replacement: '$1' }, // <https://...>, <mailto:...>, <tel:...>, <ftp://...>, etc
|
||||
{ pattern: /<([^\s@]+@[^\s@>]+)>/g, replacement: '$1' }, // <user@example.com> -> user@example.com
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
// Editor image resize options for Message Editor
|
||||
export const MESSAGE_EDITOR_IMAGE_RESIZES = [
|
||||
{
|
||||
name: 'Small',
|
||||
height: '24px',
|
||||
},
|
||||
{
|
||||
name: 'Medium',
|
||||
height: '48px',
|
||||
},
|
||||
{
|
||||
name: 'Large',
|
||||
height: '72px',
|
||||
},
|
||||
{
|
||||
name: 'Original Size',
|
||||
height: 'auto',
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,72 @@
|
||||
export default {
|
||||
GRAVATAR_URL: 'https://www.gravatar.com/avatar/',
|
||||
ASSIGNEE_TYPE: {
|
||||
ME: 'me',
|
||||
UNASSIGNED: 'unassigned',
|
||||
ALL: 'all',
|
||||
},
|
||||
STATUS_TYPE: {
|
||||
OPEN: 'open',
|
||||
RESOLVED: 'resolved',
|
||||
PENDING: 'pending',
|
||||
SNOOZED: 'snoozed',
|
||||
ALL: 'all',
|
||||
},
|
||||
SORT_BY_TYPE: {
|
||||
LAST_ACTIVITY_AT_ASC: 'last_activity_at_asc',
|
||||
LAST_ACTIVITY_AT_DESC: 'last_activity_at_desc',
|
||||
CREATED_AT_ASC: 'created_at_asc',
|
||||
CREATED_AT_DESC: 'created_at_desc',
|
||||
PRIORITY_ASC: 'priority_asc',
|
||||
PRIORITY_DESC: 'priority_desc',
|
||||
WAITING_SINCE_ASC: 'waiting_since_asc',
|
||||
WAITING_SINCE_DESC: 'waiting_since_desc',
|
||||
},
|
||||
ARTICLE_STATUS_TYPES: {
|
||||
DRAFT: 0,
|
||||
PUBLISH: 1,
|
||||
ARCHIVE: 2,
|
||||
},
|
||||
LAYOUT_TYPES: {
|
||||
CONDENSED: 'condensed',
|
||||
EXPANDED: 'expanded',
|
||||
},
|
||||
DOCS_URL: 'https://www.chatwoot.com/docs/product/',
|
||||
HELP_CENTER_DOCS_URL:
|
||||
'https://www.chatwoot.com/docs/product/others/help-center',
|
||||
TESTIMONIAL_URL:
|
||||
'https://testimonials.cdn.chatwoot.com/testimonial-content.json',
|
||||
WHATSAPP_EMBEDDED_SIGNUP_DOCS_URL:
|
||||
'https://developers.facebook.com/docs/whatsapp/embedded-signup/custom-flows/onboarding-business-app-users#limitations',
|
||||
SMALL_SCREEN_BREAKPOINT: 768,
|
||||
AVAILABILITY_STATUS_KEYS: ['online', 'busy', 'offline'],
|
||||
SNOOZE_OPTIONS: {
|
||||
UNTIL_NEXT_REPLY: 'until_next_reply',
|
||||
AN_HOUR_FROM_NOW: 'an_hour_from_now',
|
||||
UNTIL_TOMORROW: 'until_tomorrow',
|
||||
UNTIL_NEXT_WEEK: 'until_next_week',
|
||||
UNTIL_NEXT_MONTH: 'until_next_month',
|
||||
UNTIL_CUSTOM_TIME: 'until_custom_time',
|
||||
},
|
||||
EXAMPLE_URL: 'example.com',
|
||||
EXAMPLE_WEBHOOK_URL: 'https://example/api/webhook',
|
||||
INBOX_SORT_BY: {
|
||||
NEWEST: 'desc',
|
||||
OLDEST: 'asc',
|
||||
},
|
||||
INBOX_DISPLAY_BY: {
|
||||
SNOOZED: 'snoozed',
|
||||
READ: 'read',
|
||||
},
|
||||
INBOX_FILTER_TYPE: {
|
||||
STATUS: 'status',
|
||||
TYPE: 'type',
|
||||
SORT_ORDER: 'sort_order',
|
||||
},
|
||||
SLA_MISS_TYPES: {
|
||||
FRT: 'frt',
|
||||
NRT: 'nrt',
|
||||
RT: 'rt',
|
||||
},
|
||||
};
|
||||
export const DEFAULT_REDIRECT_URL = '/app/';
|
||||
@@ -0,0 +1,5 @@
|
||||
export const INSTALLATION_TYPES = {
|
||||
CLOUD: 'cloud',
|
||||
ENTERPRISE: 'enterprise',
|
||||
COMMUNITY: 'community',
|
||||
};
|
||||
@@ -0,0 +1,9 @@
|
||||
export const LOCAL_STORAGE_KEYS = {
|
||||
DISMISSED_UPDATES: 'dismissedUpdates',
|
||||
WIDGET_BUILDER: 'widgetBubble_',
|
||||
DRAFT_MESSAGES: 'draftMessages',
|
||||
COLOR_SCHEME: 'color_scheme',
|
||||
DISMISSED_LABEL_SUGGESTIONS: 'labelSuggestionsDismissed',
|
||||
MESSAGE_REPLY_TO: 'messageReplyTo',
|
||||
RECENT_SEARCHES: 'recentSearches',
|
||||
};
|
||||
@@ -0,0 +1,53 @@
|
||||
export const AVAILABLE_CUSTOM_ROLE_PERMISSIONS = [
|
||||
'conversation_manage',
|
||||
'conversation_unassigned_manage',
|
||||
'conversation_participating_manage',
|
||||
'contact_manage',
|
||||
'report_manage',
|
||||
'knowledge_base_manage',
|
||||
];
|
||||
|
||||
export const ROLES = ['agent', 'administrator'];
|
||||
|
||||
export const CONVERSATION_PERMISSIONS = [
|
||||
'conversation_manage',
|
||||
'conversation_unassigned_manage',
|
||||
'conversation_participating_manage',
|
||||
];
|
||||
|
||||
export const MANAGE_ALL_CONVERSATION_PERMISSIONS = 'conversation_manage';
|
||||
|
||||
export const CONVERSATION_UNASSIGNED_PERMISSIONS =
|
||||
'conversation_unassigned_manage';
|
||||
|
||||
export const CONVERSATION_PARTICIPATING_PERMISSIONS =
|
||||
'conversation_participating_manage';
|
||||
|
||||
export const CONTACT_PERMISSIONS = 'contact_manage';
|
||||
|
||||
export const REPORTS_PERMISSIONS = 'report_manage';
|
||||
|
||||
export const PORTAL_PERMISSIONS = 'knowledge_base_manage';
|
||||
|
||||
export const ASSIGNEE_TYPE_TAB_PERMISSIONS = {
|
||||
me: {
|
||||
count: 'mineCount',
|
||||
permissions: [...ROLES, ...CONVERSATION_PERMISSIONS],
|
||||
},
|
||||
unassigned: {
|
||||
count: 'unAssignedCount',
|
||||
permissions: [
|
||||
...ROLES,
|
||||
MANAGE_ALL_CONVERSATION_PERMISSIONS,
|
||||
CONVERSATION_UNASSIGNED_PERMISSIONS,
|
||||
],
|
||||
},
|
||||
all: {
|
||||
count: 'allCount',
|
||||
permissions: [
|
||||
...ROLES,
|
||||
MANAGE_ALL_CONVERSATION_PERMISSIONS,
|
||||
CONVERSATION_PARTICIPATING_PERMISSIONS,
|
||||
],
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,3 @@
|
||||
export const SESSION_STORAGE_KEYS = {
|
||||
IMPERSONATION_USER: 'impersonationUser',
|
||||
};
|
||||
Reference in New Issue
Block a user