@messenger-box/tailwind-ui-inbox 10.0.3-alpha.71 → 10.0.3-alpha.73

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (143) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/lib/components/AIAgent/AIAgent.d.ts +14 -0
  3. package/lib/components/AIAgent/AIAgent.d.ts.map +1 -0
  4. package/lib/components/AIAgent/AIAgent.js +1148 -0
  5. package/lib/components/AIAgent/AIAgent.js.map +1 -0
  6. package/lib/components/AIAgent/index.d.ts +2 -0
  7. package/lib/components/AIAgent/index.d.ts.map +1 -0
  8. package/lib/components/InboxMessage/InputComponent.d.ts +9 -0
  9. package/lib/components/InboxMessage/InputComponent.d.ts.map +1 -0
  10. package/lib/components/InboxMessage/InputComponent.js +210 -0
  11. package/lib/components/InboxMessage/InputComponent.js.map +1 -0
  12. package/lib/components/InboxMessage/MessageInput.d.ts.map +1 -1
  13. package/lib/components/InboxMessage/MessageInput.js +14 -10
  14. package/lib/components/InboxMessage/MessageInput.js.map +1 -1
  15. package/lib/components/InboxMessage/MessageInputComponent.d.ts +9 -0
  16. package/lib/components/InboxMessage/MessageInputComponent.d.ts.map +1 -0
  17. package/lib/components/InboxMessage/Messages.d.ts.map +1 -1
  18. package/lib/components/InboxMessage/Messages.js +4 -54
  19. package/lib/components/InboxMessage/Messages.js.map +1 -1
  20. package/lib/components/InboxMessage/MessagesBuilderUi.d.ts +17 -0
  21. package/lib/components/InboxMessage/MessagesBuilderUi.d.ts.map +1 -0
  22. package/lib/components/InboxMessage/UploadImageButton.d.ts +1 -0
  23. package/lib/components/InboxMessage/UploadImageButton.d.ts.map +1 -1
  24. package/lib/components/InboxMessage/UploadImageButton.js +3 -3
  25. package/lib/components/InboxMessage/UploadImageButton.js.map +1 -1
  26. package/lib/components/InboxMessage/index.d.ts +3 -0
  27. package/lib/components/InboxMessage/index.d.ts.map +1 -1
  28. package/lib/components/InboxMessage/message-widgets/CommonMessage.d.ts.map +1 -1
  29. package/lib/components/InboxMessage/message-widgets/CommonMessage.js +11 -6
  30. package/lib/components/InboxMessage/message-widgets/CommonMessage.js.map +1 -1
  31. package/lib/components/InboxMessage/message-widgets/ModernMessageGroup.d.ts +14 -0
  32. package/lib/components/InboxMessage/message-widgets/ModernMessageGroup.d.ts.map +1 -0
  33. package/lib/components/InboxMessage/message-widgets/ModernMessageGroup.js +1525 -0
  34. package/lib/components/InboxMessage/message-widgets/ModernMessageGroup.js.map +1 -0
  35. package/lib/components/InboxMessage/message-widgets/PlainMessage.d.ts.map +1 -1
  36. package/lib/components/InboxMessage/message-widgets/PlainMessage.js +6 -3
  37. package/lib/components/InboxMessage/message-widgets/PlainMessage.js.map +1 -1
  38. package/lib/components/InboxMessage/message-widgets/SlackLikeMessageGroup.d.ts.map +1 -1
  39. package/lib/components/InboxMessage/message-widgets/SlackLikeMessageGroup.js +207 -12
  40. package/lib/components/InboxMessage/message-widgets/SlackLikeMessageGroup.js.map +1 -1
  41. package/lib/components/InboxMessage/message-widgets/index.d.ts +1 -0
  42. package/lib/components/InboxMessage/message-widgets/index.d.ts.map +1 -1
  43. package/lib/components/index.d.ts +2 -1
  44. package/lib/components/index.d.ts.map +1 -1
  45. package/lib/compute.d.ts.map +1 -1
  46. package/lib/compute.js +79 -3
  47. package/lib/compute.js.map +1 -1
  48. package/lib/config/env-config.d.ts +6 -0
  49. package/lib/config/env-config.d.ts.map +1 -1
  50. package/lib/config/env-config.js +19 -1
  51. package/lib/config/env-config.js.map +1 -1
  52. package/lib/container/AiInbox.d.ts +15 -0
  53. package/lib/container/AiInbox.d.ts.map +1 -0
  54. package/lib/container/AiInboxWithLoader.d.ts +36 -0
  55. package/lib/container/AiInboxWithLoader.d.ts.map +1 -0
  56. package/lib/container/AiLandingInput.d.ts +4 -0
  57. package/lib/container/AiLandingInput.d.ts.map +1 -0
  58. package/lib/container/AiLandingInput.js +164 -0
  59. package/lib/container/AiLandingInput.js.map +1 -0
  60. package/lib/container/Inbox.d.ts.map +1 -1
  61. package/lib/container/Inbox.js +6 -4
  62. package/lib/container/Inbox.js.map +1 -1
  63. package/lib/container/InboxAiMessagesLoader.d.ts +36 -0
  64. package/lib/container/InboxAiMessagesLoader.d.ts.map +1 -0
  65. package/lib/container/InboxAiMessagesLoader.js +44 -0
  66. package/lib/container/InboxAiMessagesLoader.js.map +1 -0
  67. package/lib/container/InboxContainer.d.ts +12 -0
  68. package/lib/container/InboxContainer.d.ts.map +1 -0
  69. package/lib/container/InboxContainer.js +31 -0
  70. package/lib/container/InboxContainer.js.map +1 -0
  71. package/lib/container/InboxTemplate1.d.ts +15 -0
  72. package/lib/container/InboxTemplate1.d.ts.map +1 -0
  73. package/lib/container/InboxTemplate1WithLoader.d.ts +36 -0
  74. package/lib/container/InboxTemplate1WithLoader.d.ts.map +1 -0
  75. package/lib/container/InboxTemplate2.d.ts +15 -0
  76. package/lib/container/InboxTemplate2.d.ts.map +1 -0
  77. package/lib/container/InboxWithAiLoader.d.ts +15 -0
  78. package/lib/container/InboxWithAiLoader.d.ts.map +1 -0
  79. package/lib/container/InboxWithAiLoader.js +56 -0
  80. package/lib/container/InboxWithAiLoader.js.map +1 -0
  81. package/lib/container/ServiceInbox.js +1 -1
  82. package/lib/container/ServiceInbox.js.map +1 -1
  83. package/lib/container/ThreadMessages.js +1 -1
  84. package/lib/container/ThreadMessages.js.map +1 -1
  85. package/lib/container/ThreadMessagesInbox.js +1 -1
  86. package/lib/container/ThreadMessagesInbox.js.map +1 -1
  87. package/lib/container/Threads.js +1 -1
  88. package/lib/container/Threads.js.map +1 -1
  89. package/lib/container/index.d.ts +4 -1
  90. package/lib/container/index.d.ts.map +1 -1
  91. package/lib/index.d.ts +3 -2
  92. package/lib/index.d.ts.map +1 -1
  93. package/lib/index.js +1 -1
  94. package/lib/machines/aiAgentMachine.d.ts +3 -0
  95. package/lib/machines/aiAgentMachine.d.ts.map +1 -0
  96. package/lib/machines/aiAgentMachine.js +1040 -0
  97. package/lib/machines/aiAgentMachine.js.map +1 -0
  98. package/lib/machines/types.d.ts +77 -0
  99. package/lib/machines/types.d.ts.map +1 -0
  100. package/lib/routes.json +40 -0
  101. package/lib/templates/InboxWithAi.d.ts +15 -0
  102. package/lib/templates/InboxWithAi.d.ts.map +1 -0
  103. package/lib/templates/InboxWithAi.js +405 -0
  104. package/lib/templates/InboxWithAi.js.map +1 -0
  105. package/lib/templates/InboxWithAi.tsx +502 -0
  106. package/lib/templates/index.d.ts +2 -0
  107. package/lib/templates/index.d.ts.map +1 -0
  108. package/lib/templates/index.ts +1 -0
  109. package/package.json +7 -5
  110. package/src/components/AIAgent/AIAgent.tsx +1351 -0
  111. package/src/components/AIAgent/README.md +82 -0
  112. package/src/components/AIAgent/index.ts +1 -0
  113. package/src/components/InboxMessage/InputComponent.tsx +263 -0
  114. package/src/components/InboxMessage/MessageInput.tsx +73 -66
  115. package/src/components/InboxMessage/MessageInputComponent.tsx +245 -0
  116. package/src/components/InboxMessage/Messages.tsx +2 -56
  117. package/src/components/InboxMessage/MessagesBuilderUi.tsx +205 -0
  118. package/src/components/InboxMessage/UploadImageButton.tsx +3 -2
  119. package/src/components/InboxMessage/index.ts +3 -0
  120. package/src/components/InboxMessage/message-widgets/CommonMessage.tsx +39 -21
  121. package/src/components/InboxMessage/message-widgets/ModernMessageGroup.tsx +1968 -0
  122. package/src/components/InboxMessage/message-widgets/PlainMessage.tsx +6 -2
  123. package/src/components/InboxMessage/message-widgets/SlackLikeMessageGroup.tsx +306 -54
  124. package/src/components/InboxMessage/message-widgets/index.ts +1 -0
  125. package/src/components/index.ts +4 -0
  126. package/src/compute.ts +83 -2
  127. package/src/config/env-config.ts +6 -0
  128. package/src/container/AiInbox.tsx +1796 -0
  129. package/src/container/AiInboxWithLoader.tsx +356 -0
  130. package/src/container/AiLandingInput.tsx +168 -0
  131. package/src/container/Inbox.tsx +8 -5
  132. package/src/container/InboxAiMessagesLoader.tsx +58 -0
  133. package/src/container/InboxContainer.tsx +35 -0
  134. package/src/container/InboxTemplate1.tsx +1542 -0
  135. package/src/container/InboxTemplate1WithLoader.tsx +338 -0
  136. package/src/container/InboxTemplate2.tsx +1606 -0
  137. package/src/container/InboxWithAiLoader.tsx +76 -0
  138. package/src/container/index.ts +21 -1
  139. package/src/index.ts +12 -1
  140. package/src/machines/aiAgentMachine.ts +1248 -0
  141. package/src/machines/types.ts +59 -0
  142. package/src/templates/InboxWithAi.tsx +502 -0
  143. package/src/templates/index.ts +1 -0
@@ -1,14 +1,18 @@
1
1
  import React from 'react';
2
2
 
3
3
  interface IPlainMessageProps {
4
- message: string;
4
+ message: string; // may contain HTML
5
5
  index: number;
6
6
  }
7
7
 
8
8
  export const PlainMessage = ({ message, index }: IPlainMessageProps) => {
9
9
  return (
10
10
  <div className="w-full flex justify-center mb-7" key={`msgList_${index}`}>
11
- <p className="text-sm font-bold">{message}</p>
11
+ {/* <p className="text-sm font-bold">{message}</p> */}
12
+ <div
13
+ className="text-sm font-bold whitespace-pre-wrap prose prose-sm max-w-none"
14
+ dangerouslySetInnerHTML={{ __html: message }}
15
+ />
12
16
  </div>
13
17
  );
14
18
  };
@@ -57,6 +57,229 @@ export const groupMessagesByUserAndTime = (messages: IPost[], timeThresholdMinut
57
57
  return groups;
58
58
  };
59
59
 
60
+ // Detect if a string likely contains HTML
61
+ const isProbablyHTML = (value: string): boolean => {
62
+ if (!value) return false;
63
+ return /<\/?[a-z][\s\S]*>/i.test(value.trim());
64
+ };
65
+
66
+ // Minimal sanitizer without extra deps
67
+ const sanitizeHtml = (html: string): string => {
68
+ try {
69
+ if (typeof window === 'undefined' || typeof window.DOMParser === 'undefined') {
70
+ return html
71
+ .replace(/<script[\s\S]*?>[\s\S]*?<\/script>/gi, '')
72
+ .replace(/<style[\s\S]*?>[\s\S]*?<\/style>/gi, '')
73
+ .replace(/on\w+\s*=\s*"[^"]*"/gi, '')
74
+ .replace(/on\w+\s*=\s*'[^']*'/gi, '')
75
+ .replace(/on\w+\s*=\s*[^\s>]+/gi, '')
76
+ .replace(/javascript:/gi, '');
77
+ }
78
+
79
+ const parser = new window.DOMParser();
80
+ const doc = parser.parseFromString(html, 'text/html');
81
+
82
+ const dangerousTags = ['script', 'style', 'iframe', 'object', 'embed', 'link', 'meta'];
83
+ dangerousTags.forEach((tag) => {
84
+ doc.querySelectorAll(tag).forEach((el) => el.remove());
85
+ });
86
+
87
+ const walker = doc.createTreeWalker(doc.body, (NodeFilter as any).SHOW_ELEMENT);
88
+ let node = walker.nextNode() as Element | null;
89
+ while (node) {
90
+ Array.from(node.attributes).forEach((attr) => {
91
+ const name = attr.name.toLowerCase();
92
+ const value = (attr.value || '').toLowerCase();
93
+ if (name.startsWith('on') || value.startsWith('javascript:')) {
94
+ node?.removeAttribute(attr.name);
95
+ }
96
+ if ((name === 'src' || name === 'href') && !/^https?:|^\/.*/.test(attr.value)) {
97
+ node?.removeAttribute(attr.name);
98
+ }
99
+ });
100
+ node = walker.nextNode() as Element | null;
101
+ }
102
+
103
+ return doc.body.innerHTML;
104
+ } catch (e) {
105
+ return html.replace(/<script[\s\S]*?>[\s\S]*?<\/script>/gi, '');
106
+ }
107
+ };
108
+
109
+ // Render markdown-like content with fenced code blocks
110
+ const FormattedMessageContent: React.FC<{ content: string }> = ({ content }) => {
111
+ if (!content) return null;
112
+ // Normalize escaped fences (\``` -> ```)
113
+ // Unescape any backslash-escaped backticks so Markdown fences work
114
+ const normalized = content.replace(/\\`/g, '`');
115
+ const blocks = normalized.split('\n\n').filter((b) => b.trim());
116
+ return (
117
+ <div className="space-y-3">
118
+ {blocks.map((block, index) => {
119
+ const trimmed = block.trim();
120
+
121
+ // Fenced code anywhere in block
122
+ if (trimmed.includes('```')) {
123
+ const parts: React.ReactNode[] = [];
124
+ const pushText = (t: string, key: string) => {
125
+ const txt = (t || '').trim();
126
+ if (!txt) return;
127
+ if (txt.startsWith('# ')) {
128
+ parts.push(
129
+ <h1 key={key} className="text-xl font-semibold text-gray-900">
130
+ {txt.substring(2)}
131
+ </h1>,
132
+ );
133
+ return;
134
+ }
135
+ if (txt.startsWith('## ')) {
136
+ parts.push(
137
+ <h2 key={key} className="text-base font-semibold text-gray-800">
138
+ {txt.substring(3)}
139
+ </h2>,
140
+ );
141
+ return;
142
+ }
143
+ if (txt.startsWith('### ')) {
144
+ parts.push(
145
+ <h3 key={key} className="text-sm font-medium text-gray-700">
146
+ {txt.substring(4)}
147
+ </h3>,
148
+ );
149
+ return;
150
+ }
151
+ if (txt.startsWith('- ') || txt.startsWith('• ')) {
152
+ const items = txt.split('\n').filter((l) => l.trim());
153
+ parts.push(
154
+ <ul key={key} className="list-disc pl-5 space-y-1">
155
+ {items.map((it, i) => (
156
+ <li key={`${key}-li-${i}`} className="text-gray-700">
157
+ {it.replace(/^[\u2212\-•]\s*/, '')}
158
+ </li>
159
+ ))}
160
+ </ul>,
161
+ );
162
+ return;
163
+ }
164
+ if (txt.includes('**') || txt.includes('`')) {
165
+ const formatted = txt
166
+ .replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>')
167
+ .replace(/`([^`]+)`/g, '<code class="bg-gray-100 px-1 rounded">$1</code>');
168
+ parts.push(
169
+ <div
170
+ key={key}
171
+ className="text-gray-700"
172
+ dangerouslySetInnerHTML={{ __html: sanitizeHtml(formatted) }}
173
+ />,
174
+ );
175
+ return;
176
+ }
177
+ parts.push(
178
+ <p key={key} className="text-gray-700 whitespace-pre-wrap">
179
+ {txt}
180
+ </p>,
181
+ );
182
+ };
183
+
184
+ const codeRegex = /```([\w-]*)\n?([\s\S]*?)```/g;
185
+ let lastIndex = 0;
186
+ let m: RegExpExecArray | null;
187
+ while ((m = codeRegex.exec(trimmed)) !== null) {
188
+ const [full, lang, code] = m;
189
+ const before = trimmed.slice(lastIndex, m.index);
190
+ pushText(before, `${index}-before-${lastIndex}`);
191
+ const language = (lang || '').trim() || 'code';
192
+ parts.push(
193
+ <div
194
+ key={`${index}-code-${m.index}`}
195
+ className="border border-gray-200 rounded overflow-hidden"
196
+ >
197
+ <div className="px-3 py-1.5 text-[10px] font-semibold uppercase tracking-wide bg-gray-100 text-gray-600">
198
+ {language}
199
+ </div>
200
+ <div className="bg-gray-900 p-3 overflow-x-auto">
201
+ <pre className="text-xs text-gray-100 font-mono leading-relaxed not-prose">
202
+ <code>{code}</code>
203
+ </pre>
204
+ </div>
205
+ </div>,
206
+ );
207
+ lastIndex = m.index + full.length;
208
+ }
209
+ const after = trimmed.slice(lastIndex);
210
+ pushText(after, `${index}-after`);
211
+ return (
212
+ <div key={index} className="space-y-2">
213
+ {parts}
214
+ </div>
215
+ );
216
+ }
217
+
218
+ if (isProbablyHTML(trimmed)) {
219
+ return (
220
+ <div
221
+ key={index}
222
+ className="prose prose-sm max-w-none"
223
+ dangerouslySetInnerHTML={{ __html: sanitizeHtml(trimmed) }}
224
+ />
225
+ );
226
+ }
227
+
228
+ if (trimmed.startsWith('### '))
229
+ return (
230
+ <h3 key={index} className="text-sm font-medium text-gray-700">
231
+ {trimmed.substring(4)}
232
+ </h3>
233
+ );
234
+ if (trimmed.startsWith('## '))
235
+ return (
236
+ <h2 key={index} className="text-base font-semibold text-gray-800">
237
+ {trimmed.substring(3)}
238
+ </h2>
239
+ );
240
+ if (trimmed.startsWith('# '))
241
+ return (
242
+ <h1 key={index} className="text-xl font-semibold text-gray-900">
243
+ {trimmed.substring(2)}
244
+ </h1>
245
+ );
246
+
247
+ if (trimmed.startsWith('- ') || trimmed.startsWith('• ')) {
248
+ const items = trimmed.split('\n').filter((l) => l.trim());
249
+ return (
250
+ <ul key={index} className="list-disc pl-5 space-y-1">
251
+ {items.map((it, i) => (
252
+ <li key={`${index}-li-${i}`} className="text-gray-700">
253
+ {it.replace(/^[\u2212\-•]\s*/, '')}
254
+ </li>
255
+ ))}
256
+ </ul>
257
+ );
258
+ }
259
+
260
+ if (trimmed.includes('**') || trimmed.includes('`')) {
261
+ const formatted = trimmed
262
+ .replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>')
263
+ .replace(/`([^`]+)`/g, '<code class="bg-gray-100 px-1 rounded">$1</code>');
264
+ return (
265
+ <div
266
+ key={index}
267
+ className="text-gray-700"
268
+ dangerouslySetInnerHTML={{ __html: sanitizeHtml(formatted) }}
269
+ />
270
+ );
271
+ }
272
+
273
+ return (
274
+ <p key={index} className="text-gray-700 whitespace-pre-wrap">
275
+ {trimmed}
276
+ </p>
277
+ );
278
+ })}
279
+ </div>
280
+ );
281
+ };
282
+
60
283
  const MessageGroup: React.FC<MessageGroupProps> = ({
61
284
  author,
62
285
  messages,
@@ -78,6 +301,12 @@ const MessageGroup: React.FC<MessageGroupProps> = ({
78
301
  return format(date, 'h:mm a');
79
302
  };
80
303
 
304
+ // Determine if this is an AI/system message for special styling
305
+ const isSystemMessage =
306
+ author?.username?.toLowerCase().includes('ai') ||
307
+ author?.username?.toLowerCase().includes('assistant') ||
308
+ author?.username?.toLowerCase().includes('system');
309
+
81
310
  return (
82
311
  <div
83
312
  className={`group hover:bg-white hover:bg-opacity-60 rounded transition-colors ${
@@ -89,30 +318,34 @@ const MessageGroup: React.FC<MessageGroupProps> = ({
89
318
  isDesktopView ? 'space-x-4' : isSmallScreen ? 'space-x-2' : 'space-x-3'
90
319
  }`}
91
320
  >
92
- {/* Avatar - show for all messages */}
93
- <div className="flex-shrink-0 mt-0.5">
94
- <img
95
- className={`rounded-lg cursor-pointer hover:opacity-80 transition-opacity ${
96
- isDesktopView ? 'w-12 h-12' : isSmallScreen ? 'w-8 h-8' : 'w-10 h-10'
97
- }`}
98
- src={author?.picture || '/default-avatar.svg'}
99
- alt={authorName}
100
- onClick={() => onOpen(firstMessage)}
101
- onError={(e) => {
102
- e.currentTarget.src = '/default-avatar.svg';
103
- }}
104
- />
105
- </div>
321
+ {/* Avatar - Only show for non-system messages */}
322
+ {!isSystemMessage && (
323
+ <div className="flex-shrink-0 mt-0.5">
324
+ <img
325
+ className={`rounded-lg cursor-pointer hover:opacity-80 transition-opacity ${
326
+ isDesktopView ? 'w-12 h-12' : isSmallScreen ? 'w-8 h-8' : 'w-10 h-10'
327
+ }`}
328
+ src={author?.picture || '/default-avatar.svg'}
329
+ alt={authorName}
330
+ onClick={() => onOpen(firstMessage)}
331
+ onError={(e) => {
332
+ e.currentTarget.src = '/default-avatar.svg';
333
+ }}
334
+ />
335
+ </div>
336
+ )}
106
337
 
107
338
  <div className="flex-1 min-w-0 overflow-hidden">
108
- {/* Author name and timestamp - show for all messages */}
109
- <div className="flex items-center space-x-2 mb-1">
110
- <span className="text-sm font-semibold text-gray-900 truncate">{authorName}</span>
111
- <span className="text-xs text-gray-500 flex-shrink-0">
112
- {formatTime(firstMessage.createdAt)}
113
- </span>
114
- {isOwnMessage && <span className="text-xs text-gray-400 italic flex-shrink-0">(you)</span>}
115
- </div>
339
+ {/* Author name and timestamp - Only show for non-system messages */}
340
+ {!isSystemMessage && (
341
+ <div className="flex items-center space-x-2 mb-1">
342
+ <span className="text-sm font-semibold text-gray-900 truncate">{authorName}</span>
343
+ <span className="text-xs text-gray-500 flex-shrink-0">
344
+ {formatTime(firstMessage.createdAt)}
345
+ </span>
346
+ {isOwnMessage && <span className="text-xs text-gray-400 italic flex-shrink-0">(you)</span>}
347
+ </div>
348
+ )}
116
349
 
117
350
  {/* Messages in the group - single line for each message */}
118
351
  <div className="space-y-0.5">
@@ -121,6 +354,7 @@ const MessageGroup: React.FC<MessageGroupProps> = ({
121
354
  key={message.id}
122
355
  message={message}
123
356
  isOwnMessage={isOwnMessage}
357
+ isSystemMessage={isSystemMessage}
124
358
  isFirstInGroup={index === 0}
125
359
  isLastInGroup={index === messages.length - 1}
126
360
  showTimestamp={isOwnMessage && index === 0}
@@ -147,11 +381,13 @@ interface MessageBubbleProps {
147
381
  totalInGroup: number;
148
382
  authorName: string;
149
383
  formatTime: (timestamp: string) => string;
384
+ isSystemMessage: boolean;
150
385
  }
151
386
 
152
387
  const MessageBubble: React.FC<MessageBubbleProps> = ({
153
388
  message,
154
389
  isOwnMessage,
390
+ isSystemMessage,
155
391
  isFirstInGroup,
156
392
  isLastInGroup,
157
393
  showTimestamp,
@@ -161,45 +397,61 @@ const MessageBubble: React.FC<MessageBubbleProps> = ({
161
397
  formatTime,
162
398
  }) => {
163
399
  const handleClick = () => {
164
- onMessageClick?.(message);
400
+ if (!isSystemMessage) {
401
+ onMessageClick?.(message);
402
+ }
165
403
  };
166
404
 
167
405
  // All messages use the same format (Slack style - left aligned)
168
406
  return (
169
- <div className="py-1 hover:bg-gray-50 hover:bg-opacity-50 rounded px-1 sm:px-2 -mx-1 sm:-mx-2 group relative">
170
- <div
171
- className="text-sm text-gray-900 cursor-pointer hover:bg-gray-100 px-1 sm:px-2 py-1 rounded"
172
- onClick={handleClick}
173
- >
174
- {/* Show timestamp on hover */}
175
- <span className="text-xs text-gray-500 opacity-0 group-hover:opacity-100 transition-opacity absolute right-1 sm:right-2 top-1">
176
- {formatTime(message.createdAt)}
177
- </span>
178
-
179
- {message.message && (
180
- <div className="whitespace-pre-wrap break-words leading-relaxed pr-12 sm:pr-16">
181
- {message.message}
182
- </div>
183
- )}
407
+ <div
408
+ className={`py-1 hover:bg-gray-50 hover:bg-opacity-50 rounded px-1 sm:px-2 -mx-1 sm:-mx-2 group ${
409
+ isSystemMessage ? '' : 'cursor-pointer'
410
+ }`}
411
+ >
412
+ <div className="flex items-start justify-between gap-2">
413
+ <div
414
+ className={`text-sm hover:bg-gray-100 px-1 sm:px-2 py-1 rounded flex-1 ${
415
+ isSystemMessage ? 'text-gray-800' : 'text-gray-900 cursor-pointer'
416
+ }`}
417
+ onClick={handleClick}
418
+ >
419
+ {message.message && (
420
+ <div className="break-words leading-relaxed">
421
+ {message.message.includes('```') ? (
422
+ <FormattedMessageContent content={message.message} />
423
+ ) : isProbablyHTML(message.message) ? (
424
+ <div
425
+ className="prose prose-sm max-w-none"
426
+ dangerouslySetInnerHTML={{ __html: sanitizeHtml(message.message) }}
427
+ />
428
+ ) : (
429
+ <FormattedMessageContent content={message.message} />
430
+ )}
431
+ </div>
432
+ )}
184
433
 
185
- {message.files?.totalCount > 0 && (
186
- <div className="mt-2 pr-12 sm:pr-16">
187
- <FilesList uploaded files={message.files.data} />
188
- </div>
189
- )}
434
+ {message.files?.totalCount > 0 && (
435
+ <div className="mt-2">
436
+ <FilesList uploaded files={message.files.data} />
437
+ </div>
438
+ )}
439
+ </div>
190
440
 
191
- {/* Show delivery status for own messages */}
192
- {/* {isOwnMessage && message.isDelivered !== undefined && (
193
- <div className="text-xs text-gray-400 mt-1 clear-both">
194
- {message.isDelivered
195
- ? message.isRead
196
- ? '✓✓ Read'
197
- : '✓✓ Delivered'
198
- : '✓ Sent'
199
- }
200
- </div>
201
- )} */}
441
+ {/* Show timestamp to the right of message */}
442
+ <span className="text-xs text-gray-500 flex-shrink-0 mt-1">{formatTime(message.createdAt)}</span>
202
443
  </div>
444
+
445
+ {/* Show delivery status for own messages */}
446
+ {/* {isOwnMessage && message.isDelivered !== undefined && (
447
+ <div className="text-xs text-gray-400 mt-1 clear-both">
448
+ {message.isDelivered
449
+ ? message.isRead
450
+ ? '✓✓ Read'
451
+ : '✓✓ Delivered'
452
+ : '✓ Sent'}
453
+ </div>
454
+ )} */}
203
455
  </div>
204
456
  );
205
457
  };
@@ -1,2 +1,3 @@
1
1
  export { MessageSliceRenderer } from './MessageSliceRenderer';
2
2
  export { SlackLikeMessageGroup } from './SlackLikeMessageGroup';
3
+ export { ModernMessageGroupComponent } from './ModernMessageGroup';
@@ -3,6 +3,8 @@ export {
3
3
  LeftSidebar,
4
4
  RightSidebar,
5
5
  MessageInput,
6
+ MessageInputComponent,
7
+ InputComponent,
6
8
  Messages,
7
9
  CommonMessage,
8
10
  MessageSliceRenderer,
@@ -11,5 +13,7 @@ export {
11
13
  UploadImageButton,
12
14
  UserModalContent,
13
15
  ServiceInboxItem,
16
+ MessagesBuilderUi,
14
17
  } from './InboxMessage';
15
18
  export { ChatMessageFiller, ChatMessageFill2 } from './slot-fill';
19
+ export { AIAgent } from './AIAgent';
package/src/compute.ts CHANGED
@@ -25,7 +25,7 @@ export const messengerPageStore: IRouteModule[] | { [key: string]: any } = [
25
25
  component: () => import('./container/InboxWithLoader'),
26
26
  tab: 'Chat App',
27
27
  position: IMenuPosition.Middle,
28
- // authority: [PreDefineAccountPermissions.secureUser],
28
+ //authority: [PreDefineAccountPermissions.secureUser],
29
29
  name: 'Inbox',
30
30
  path: '/o/:orgName/inbox',
31
31
  },
@@ -41,10 +41,91 @@ export const messengerPageStore: IRouteModule[] | { [key: string]: any } = [
41
41
  path: '//o/:orgName/direct-message/:id?/:postId?',
42
42
  // path: '/o/:orgName/inbox',
43
43
  },
44
+ // {
45
+ // exact: false,
46
+ // icon: 'AiOutlineInbox',
47
+ // key: 'ai-messenger',
48
+ // component: () => import('./container/AiInboxWithLoader'),
49
+ // tab: 'DM',
50
+ // position: IMenuPosition.Middle,
51
+ // // authority: [PreDefineAccountPermissions.secureUser],
52
+ // name: 'AiMessenger',
53
+ // path: '//o/:orgName/ai-messenger/:id?/:postId?',
54
+ // // path: '/o/:orgName/inbox',
55
+ // },
56
+ {
57
+ exact: false,
58
+ icon: 'AiOutlineInbox',
59
+ key: 'ai-messenger',
60
+ component: () => import('./container/InboxWithAiLoader'),
61
+ tab: 'Ai Messenger',
62
+ position: IMenuPosition.Middle,
63
+ name: 'AiMessenger',
64
+ path: '/ai-messenger',
65
+ },
66
+ {
67
+ exact: false,
68
+ icon: 'AiOutlineInbox',
69
+ key: 'ai-messenger-with-org-name',
70
+ component: () => import('./container/InboxWithAiLoader'),
71
+ tab: 'Ai Messenger',
72
+ position: IMenuPosition.Middle,
73
+ name: 'AiMessengerWithOrgName',
74
+ path: '//o/:orgName/ai-messenger',
75
+ },
76
+ // {
77
+ // exact: false,
78
+ // icon: 'AiOutlineInbox',
79
+ // key: 'ai-messenger-with-channel-id',
80
+ // component: () => import('./templates/InboxWithAi'),
81
+ // tab: 'Ai Messenger',
82
+ // position: IMenuPosition.Middle,
83
+ // name: 'AiMessengerWithChannelId',
84
+ // path: '//o?/:orgName?/ai-messenger/:id',
85
+ // },
86
+
87
+ // {
88
+ // exact: false,
89
+ // icon: 'AiOutlineInbox',
90
+ // key: 'messenger-ai',
91
+ // component: () => import('./container/InboxAiLoader'),
92
+ // tab: 'Ai Messenger',
93
+ // position: IMenuPosition.Middle,
94
+ // name: 'MessengerAi',
95
+ // path: '/messenger-ai',
96
+ // },
97
+ {
98
+ exact: false,
99
+ icon: 'AiOutlineInbox',
100
+ key: 'ai-messenger-with-message-app',
101
+ component: () => import('./container/InboxAiMessagesLoader'),
102
+ tab: 'Ai Messenger',
103
+ position: IMenuPosition.Middle,
104
+ name: 'AiMessengerWithMessageApp',
105
+ path: '/ai-messenger/app',
106
+ },
107
+ // {
108
+ // exact: false,
109
+ // icon: 'AiOutlineInbox',
110
+ // key: 'ai-messenger-with-preview',
111
+ // component: () => import('./container/InboxWithAiLoader'),
112
+ // tab: 'Ai Messenger',
113
+ // position: IMenuPosition.Middle,
114
+ // name: 'AiMessengerWithPreview',
115
+ // path: '//o?/:orgName?/ai-messenger/app/:id/preview',
116
+ // },
44
117
  ];
45
118
 
46
119
  // get only selected Routes to work
47
- const selectedRoutes = ['inbox', 'direct-message'];
120
+ const selectedRoutes = [
121
+ 'inbox',
122
+ 'direct-message',
123
+ 'ai-messenger',
124
+ 'ai-messenger-with-org-name',
125
+ 'ai-messenger-with-channel-id',
126
+ 'ai-messenger-with-message-app',
127
+ 'ai-messenger-with-preview',
128
+ ];
48
129
 
49
130
  const filteredRoutes = getFilteredRoutes(messengerPageStore, selectedRoutes);
50
131
 
@@ -4,8 +4,14 @@ import { getEnvironment } from '@common-stack/core';
4
4
  const env = getEnvironment();
5
5
 
6
6
  export const config = cleanEnv(env, {
7
+ CLIENT_URL: str({ default: 'http://localhost:3011' }),
7
8
  WEB_INBOX_MESSEGE_PATH: str({ default: 'inbox' }),
8
9
  WEB_THREAD_MESSEGE_PATH: str({ default: 'thread' }),
9
10
  MESSAGES_PER_PAGE: num({ devDefault: 10, default: 10 }),
10
11
  FILES_PER_MESSAGE: num({ default: 10 }),
12
+ VITE_OPENAI_API_KEY: str({ default: '' }),
13
+ VITE_ANTHROPIC_API_KEY: str({ default: '' }),
14
+ ANTHROPIC_API_KEY: str({ default: '' }),
15
+ NEWS_API_KEY: str({ default: '' }),
16
+ OPENAI_API_KEY: str({ default: '' }),
11
17
  });