@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.
- package/CHANGELOG.md +8 -0
- package/lib/components/AIAgent/AIAgent.d.ts +14 -0
- package/lib/components/AIAgent/AIAgent.d.ts.map +1 -0
- package/lib/components/AIAgent/AIAgent.js +1148 -0
- package/lib/components/AIAgent/AIAgent.js.map +1 -0
- package/lib/components/AIAgent/index.d.ts +2 -0
- package/lib/components/AIAgent/index.d.ts.map +1 -0
- package/lib/components/InboxMessage/InputComponent.d.ts +9 -0
- package/lib/components/InboxMessage/InputComponent.d.ts.map +1 -0
- package/lib/components/InboxMessage/InputComponent.js +210 -0
- package/lib/components/InboxMessage/InputComponent.js.map +1 -0
- package/lib/components/InboxMessage/MessageInput.d.ts.map +1 -1
- package/lib/components/InboxMessage/MessageInput.js +14 -10
- package/lib/components/InboxMessage/MessageInput.js.map +1 -1
- package/lib/components/InboxMessage/MessageInputComponent.d.ts +9 -0
- package/lib/components/InboxMessage/MessageInputComponent.d.ts.map +1 -0
- package/lib/components/InboxMessage/Messages.d.ts.map +1 -1
- package/lib/components/InboxMessage/Messages.js +4 -54
- package/lib/components/InboxMessage/Messages.js.map +1 -1
- package/lib/components/InboxMessage/MessagesBuilderUi.d.ts +17 -0
- package/lib/components/InboxMessage/MessagesBuilderUi.d.ts.map +1 -0
- package/lib/components/InboxMessage/UploadImageButton.d.ts +1 -0
- package/lib/components/InboxMessage/UploadImageButton.d.ts.map +1 -1
- package/lib/components/InboxMessage/UploadImageButton.js +3 -3
- package/lib/components/InboxMessage/UploadImageButton.js.map +1 -1
- package/lib/components/InboxMessage/index.d.ts +3 -0
- package/lib/components/InboxMessage/index.d.ts.map +1 -1
- package/lib/components/InboxMessage/message-widgets/CommonMessage.d.ts.map +1 -1
- package/lib/components/InboxMessage/message-widgets/CommonMessage.js +11 -6
- package/lib/components/InboxMessage/message-widgets/CommonMessage.js.map +1 -1
- package/lib/components/InboxMessage/message-widgets/ModernMessageGroup.d.ts +14 -0
- package/lib/components/InboxMessage/message-widgets/ModernMessageGroup.d.ts.map +1 -0
- package/lib/components/InboxMessage/message-widgets/ModernMessageGroup.js +1525 -0
- package/lib/components/InboxMessage/message-widgets/ModernMessageGroup.js.map +1 -0
- package/lib/components/InboxMessage/message-widgets/PlainMessage.d.ts.map +1 -1
- package/lib/components/InboxMessage/message-widgets/PlainMessage.js +6 -3
- package/lib/components/InboxMessage/message-widgets/PlainMessage.js.map +1 -1
- package/lib/components/InboxMessage/message-widgets/SlackLikeMessageGroup.d.ts.map +1 -1
- package/lib/components/InboxMessage/message-widgets/SlackLikeMessageGroup.js +207 -12
- package/lib/components/InboxMessage/message-widgets/SlackLikeMessageGroup.js.map +1 -1
- package/lib/components/InboxMessage/message-widgets/index.d.ts +1 -0
- package/lib/components/InboxMessage/message-widgets/index.d.ts.map +1 -1
- package/lib/components/index.d.ts +2 -1
- package/lib/components/index.d.ts.map +1 -1
- package/lib/compute.d.ts.map +1 -1
- package/lib/compute.js +79 -3
- package/lib/compute.js.map +1 -1
- package/lib/config/env-config.d.ts +6 -0
- package/lib/config/env-config.d.ts.map +1 -1
- package/lib/config/env-config.js +19 -1
- package/lib/config/env-config.js.map +1 -1
- package/lib/container/AiInbox.d.ts +15 -0
- package/lib/container/AiInbox.d.ts.map +1 -0
- package/lib/container/AiInboxWithLoader.d.ts +36 -0
- package/lib/container/AiInboxWithLoader.d.ts.map +1 -0
- package/lib/container/AiLandingInput.d.ts +4 -0
- package/lib/container/AiLandingInput.d.ts.map +1 -0
- package/lib/container/AiLandingInput.js +164 -0
- package/lib/container/AiLandingInput.js.map +1 -0
- package/lib/container/Inbox.d.ts.map +1 -1
- package/lib/container/Inbox.js +6 -4
- package/lib/container/Inbox.js.map +1 -1
- package/lib/container/InboxAiMessagesLoader.d.ts +36 -0
- package/lib/container/InboxAiMessagesLoader.d.ts.map +1 -0
- package/lib/container/InboxAiMessagesLoader.js +44 -0
- package/lib/container/InboxAiMessagesLoader.js.map +1 -0
- package/lib/container/InboxContainer.d.ts +12 -0
- package/lib/container/InboxContainer.d.ts.map +1 -0
- package/lib/container/InboxContainer.js +31 -0
- package/lib/container/InboxContainer.js.map +1 -0
- package/lib/container/InboxTemplate1.d.ts +15 -0
- package/lib/container/InboxTemplate1.d.ts.map +1 -0
- package/lib/container/InboxTemplate1WithLoader.d.ts +36 -0
- package/lib/container/InboxTemplate1WithLoader.d.ts.map +1 -0
- package/lib/container/InboxTemplate2.d.ts +15 -0
- package/lib/container/InboxTemplate2.d.ts.map +1 -0
- package/lib/container/InboxWithAiLoader.d.ts +15 -0
- package/lib/container/InboxWithAiLoader.d.ts.map +1 -0
- package/lib/container/InboxWithAiLoader.js +56 -0
- package/lib/container/InboxWithAiLoader.js.map +1 -0
- package/lib/container/ServiceInbox.js +1 -1
- package/lib/container/ServiceInbox.js.map +1 -1
- package/lib/container/ThreadMessages.js +1 -1
- package/lib/container/ThreadMessages.js.map +1 -1
- package/lib/container/ThreadMessagesInbox.js +1 -1
- package/lib/container/ThreadMessagesInbox.js.map +1 -1
- package/lib/container/Threads.js +1 -1
- package/lib/container/Threads.js.map +1 -1
- package/lib/container/index.d.ts +4 -1
- package/lib/container/index.d.ts.map +1 -1
- package/lib/index.d.ts +3 -2
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -1
- package/lib/machines/aiAgentMachine.d.ts +3 -0
- package/lib/machines/aiAgentMachine.d.ts.map +1 -0
- package/lib/machines/aiAgentMachine.js +1040 -0
- package/lib/machines/aiAgentMachine.js.map +1 -0
- package/lib/machines/types.d.ts +77 -0
- package/lib/machines/types.d.ts.map +1 -0
- package/lib/routes.json +40 -0
- package/lib/templates/InboxWithAi.d.ts +15 -0
- package/lib/templates/InboxWithAi.d.ts.map +1 -0
- package/lib/templates/InboxWithAi.js +405 -0
- package/lib/templates/InboxWithAi.js.map +1 -0
- package/lib/templates/InboxWithAi.tsx +502 -0
- package/lib/templates/index.d.ts +2 -0
- package/lib/templates/index.d.ts.map +1 -0
- package/lib/templates/index.ts +1 -0
- package/package.json +7 -5
- package/src/components/AIAgent/AIAgent.tsx +1351 -0
- package/src/components/AIAgent/README.md +82 -0
- package/src/components/AIAgent/index.ts +1 -0
- package/src/components/InboxMessage/InputComponent.tsx +263 -0
- package/src/components/InboxMessage/MessageInput.tsx +73 -66
- package/src/components/InboxMessage/MessageInputComponent.tsx +245 -0
- package/src/components/InboxMessage/Messages.tsx +2 -56
- package/src/components/InboxMessage/MessagesBuilderUi.tsx +205 -0
- package/src/components/InboxMessage/UploadImageButton.tsx +3 -2
- package/src/components/InboxMessage/index.ts +3 -0
- package/src/components/InboxMessage/message-widgets/CommonMessage.tsx +39 -21
- package/src/components/InboxMessage/message-widgets/ModernMessageGroup.tsx +1968 -0
- package/src/components/InboxMessage/message-widgets/PlainMessage.tsx +6 -2
- package/src/components/InboxMessage/message-widgets/SlackLikeMessageGroup.tsx +306 -54
- package/src/components/InboxMessage/message-widgets/index.ts +1 -0
- package/src/components/index.ts +4 -0
- package/src/compute.ts +83 -2
- package/src/config/env-config.ts +6 -0
- package/src/container/AiInbox.tsx +1796 -0
- package/src/container/AiInboxWithLoader.tsx +356 -0
- package/src/container/AiLandingInput.tsx +168 -0
- package/src/container/Inbox.tsx +8 -5
- package/src/container/InboxAiMessagesLoader.tsx +58 -0
- package/src/container/InboxContainer.tsx +35 -0
- package/src/container/InboxTemplate1.tsx +1542 -0
- package/src/container/InboxTemplate1WithLoader.tsx +338 -0
- package/src/container/InboxTemplate2.tsx +1606 -0
- package/src/container/InboxWithAiLoader.tsx +76 -0
- package/src/container/index.ts +21 -1
- package/src/index.ts +12 -1
- package/src/machines/aiAgentMachine.ts +1248 -0
- package/src/machines/types.ts +59 -0
- package/src/templates/InboxWithAi.tsx +502 -0
- 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
|
|
93
|
-
|
|
94
|
-
<
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
e
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
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
|
|
109
|
-
|
|
110
|
-
<
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
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
|
-
|
|
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
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
<
|
|
176
|
-
{
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
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
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
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
|
|
192
|
-
|
|
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
|
};
|
package/src/components/index.ts
CHANGED
|
@@ -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
|
-
//
|
|
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 = [
|
|
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
|
|
package/src/config/env-config.ts
CHANGED
|
@@ -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
|
});
|