@messenger-box/tailwind-ui-inbox 10.0.3-alpha.72 → 10.0.3-alpha.74
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 +7 -0
- package/lib/components/AIAgent/AIAgent.d.ts.map +1 -1
- package/lib/components/AIAgent/AIAgent.js +362 -615
- package/lib/components/AIAgent/AIAgent.js.map +1 -1
- package/lib/components/InboxMessage/InputComponent.d.ts.map +1 -1
- package/lib/components/InboxMessage/InputComponent.js +143 -140
- package/lib/components/InboxMessage/InputComponent.js.map +1 -1
- package/lib/components/InboxMessage/RightSidebarAi.d.ts +23 -0
- package/lib/components/InboxMessage/RightSidebarAi.d.ts.map +1 -0
- package/lib/components/InboxMessage/RightSidebarAi.js +9 -0
- package/lib/components/InboxMessage/RightSidebarAi.js.map +1 -0
- package/lib/components/InboxMessage/index.d.ts +1 -0
- package/lib/components/InboxMessage/index.d.ts.map +1 -1
- package/lib/components/InboxMessage/message-widgets/ErrorFixCard.d.ts +11 -0
- package/lib/components/InboxMessage/message-widgets/ErrorFixCard.d.ts.map +1 -0
- package/lib/components/InboxMessage/message-widgets/ErrorFixCard.js +194 -0
- package/lib/components/InboxMessage/message-widgets/ErrorFixCard.js.map +1 -0
- package/lib/components/InboxMessage/message-widgets/ModernMessageGroup.d.ts +5 -1
- package/lib/components/InboxMessage/message-widgets/ModernMessageGroup.d.ts.map +1 -1
- package/lib/components/InboxMessage/message-widgets/ModernMessageGroup.js +308 -857
- package/lib/components/InboxMessage/message-widgets/ModernMessageGroup.js.map +1 -1
- package/lib/components/ModelConfigPanel.d.ts +12 -0
- package/lib/components/ModelConfigPanel.d.ts.map +1 -0
- package/lib/components/ModelConfigPanel.js +304 -0
- package/lib/components/ModelConfigPanel.js.map +1 -0
- package/lib/components/filler-components/RightSiderBar.d.ts +24 -0
- package/lib/components/filler-components/RightSiderBar.d.ts.map +1 -0
- package/lib/components/filler-components/RightSiderBar.js +335 -0
- package/lib/components/filler-components/RightSiderBar.js.map +1 -0
- package/lib/components/index.d.ts +4 -2
- package/lib/components/index.d.ts.map +1 -1
- package/lib/components/live-code-editor/hybrid-live-editor.d.ts +20 -0
- package/lib/components/live-code-editor/hybrid-live-editor.d.ts.map +1 -0
- package/lib/components/live-code-editor/hybrid-live-editor.js +68 -0
- package/lib/components/live-code-editor/hybrid-live-editor.js.map +1 -0
- package/lib/components/live-code-editor/index.d.ts +4 -0
- package/lib/components/live-code-editor/index.d.ts.map +1 -0
- package/lib/components/live-code-editor/live-code-editor.d.ts +14 -0
- package/lib/components/live-code-editor/live-code-editor.d.ts.map +1 -0
- package/lib/components/live-code-editor/live-code-editor.js +207 -0
- package/lib/components/live-code-editor/live-code-editor.js.map +1 -0
- package/lib/components/slot-fill/chat-message-filler.js +1 -1
- package/lib/components/slot-fill/chat-message-filler.js.map +1 -1
- package/lib/components/slot-fill/index.d.ts +1 -0
- package/lib/components/slot-fill/index.d.ts.map +1 -1
- package/lib/components/slot-fill/right-sidebar-filler.d.ts +4 -0
- package/lib/components/slot-fill/right-sidebar-filler.d.ts.map +1 -0
- package/lib/components/slot-fill/right-sidebar-filler.js +13 -0
- package/lib/components/slot-fill/right-sidebar-filler.js.map +1 -0
- package/lib/components/ui/button.d.ts +9 -0
- package/lib/components/ui/button.d.ts.map +1 -0
- package/lib/compute.js +1 -2
- package/lib/container/AiInbox.d.ts.map +1 -1
- package/lib/container/AiLandingInput.d.ts.map +1 -1
- package/lib/container/AiLandingInput.js +46 -119
- package/lib/container/AiLandingInput.js.map +1 -1
- package/lib/container/Inbox.js +1 -1
- package/lib/container/Inbox.js.map +1 -1
- package/lib/container/InboxAiMessagesLoader.d.ts +0 -21
- package/lib/container/InboxAiMessagesLoader.d.ts.map +1 -1
- package/lib/container/InboxAiMessagesLoader.js +18 -35
- package/lib/container/InboxAiMessagesLoader.js.map +1 -1
- 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 +5 -4
- package/lib/container/index.d.ts.map +1 -1
- package/lib/enums/messenger-slot-fill-name-enum.d.ts +2 -1
- package/lib/enums/messenger-slot-fill-name-enum.d.ts.map +1 -1
- package/lib/enums/messenger-slot-fill-name-enum.js +1 -0
- package/lib/enums/messenger-slot-fill-name-enum.js.map +1 -1
- package/lib/hooks/index.d.ts +3 -0
- package/lib/hooks/index.d.ts.map +1 -0
- package/lib/hooks/use-file-sync.d.ts +16 -0
- package/lib/hooks/use-file-sync.d.ts.map +1 -0
- package/lib/hooks/use-file-sync.js +63 -0
- package/lib/hooks/use-file-sync.js.map +1 -0
- package/lib/hooks/usePersistentModelConfig.d.ts +15 -0
- package/lib/hooks/usePersistentModelConfig.d.ts.map +1 -0
- package/lib/hooks/usePersistentModelConfig.js +46 -0
- package/lib/hooks/usePersistentModelConfig.js.map +1 -0
- package/lib/index.d.ts +5 -2
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -1
- package/lib/machines/aiAgentMachine.d.ts.map +1 -1
- package/lib/machines/aiAgentMachine.js +64 -21
- package/lib/machines/aiAgentMachine.js.map +1 -1
- package/lib/machines/aiAgentMachine.simple.d.ts +3 -0
- package/lib/machines/aiAgentMachine.simple.d.ts.map +1 -0
- package/lib/machines/aiAgentMachine.simple.js +108 -0
- package/lib/machines/aiAgentMachine.simple.js.map +1 -0
- package/lib/machines/index.d.ts +3 -0
- package/lib/machines/index.d.ts.map +1 -0
- package/lib/module.d.ts +2 -1
- package/lib/module.d.ts.map +1 -1
- package/lib/module.js +11 -3
- package/lib/module.js.map +1 -1
- package/lib/routes.json +1 -2
- package/lib/templates/InboxWithAi.d.ts.map +1 -1
- package/lib/templates/InboxWithAi.js +129 -70
- package/lib/templates/InboxWithAi.js.map +1 -1
- package/lib/templates/InboxWithAi.tsx +151 -90
- 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/lib/utils/utils.d.ts +2 -0
- package/lib/utils/utils.d.ts.map +1 -0
- package/lib/utils/utils.js +3 -0
- package/lib/utils/utils.js.map +1 -0
- package/package.json +8 -5
- package/src/components/AIAgent/AIAgent.tsx +469 -731
- package/src/components/AIAgent/AIAgent.tsx.bk +1365 -0
- package/src/components/InboxMessage/InputComponent.tsx +2 -1
- package/src/components/InboxMessage/RightSidebarAi.tsx +37 -0
- package/src/components/InboxMessage/index.ts +1 -0
- package/src/components/InboxMessage/message-widgets/ErrorFixCard.tsx +240 -0
- package/src/components/InboxMessage/message-widgets/ModernMessageGroup.tsx +337 -1116
- package/src/components/ModelConfigPanel.tsx +334 -0
- package/src/components/filler-components/RightSiderBar.tsx +408 -0
- package/src/components/index.ts +4 -1
- package/src/components/live-code-editor/hybrid-live-editor.tsx +105 -0
- package/src/components/live-code-editor/index.ts +3 -0
- package/src/components/live-code-editor/live-code-editor.tsx +257 -0
- package/src/components/slot-fill/index.ts +1 -0
- package/src/components/slot-fill/right-sidebar-filler.tsx +39 -0
- package/src/components/ui/button.tsx +32 -0
- package/src/container/AiInbox.tsx +26 -3
- package/src/container/AiLandingInput.tsx +48 -22
- package/src/container/InboxAiMessagesLoader.tsx +17 -41
- package/src/container/index.ts +14 -6
- package/src/enums/messenger-slot-fill-name-enum.ts +1 -0
- package/src/hooks/index.ts +2 -0
- package/src/hooks/use-file-sync.ts +91 -0
- package/src/hooks/usePersistentModelConfig.ts +63 -0
- package/src/index.ts +19 -1
- package/src/machines/aiAgentMachine.simple.ts +89 -0
- package/src/machines/aiAgentMachine.ts +67 -19
- package/src/machines/aiAgentMachine.ts.bk +1296 -0
- package/src/machines/index.ts +2 -0
- package/src/module.tsx +10 -1
- package/src/templates/InboxWithAi.tsx +151 -90
- package/src/templates/index.ts +1 -0
- package/src/utils/utils.ts +3 -0
- package/lib/components/InboxMessage/MessageInputComponent.js +0 -173
- package/lib/components/InboxMessage/MessageInputComponent.js.map +0 -1
- package/lib/components/InboxMessage/MessagesBuilderUi.js +0 -162
- package/lib/components/InboxMessage/MessagesBuilderUi.js.map +0 -1
- package/lib/container/AiInbox.js +0 -1520
- package/lib/container/AiInbox.js.map +0 -1
- package/lib/container/AiInboxWithLoader.js +0 -300
- package/lib/container/AiInboxWithLoader.js.map +0 -1
- package/lib/container/InboxTemplate1.js +0 -1375
- package/lib/container/InboxTemplate1.js.map +0 -1
- package/lib/container/InboxTemplate2.js +0 -1426
- package/lib/container/InboxTemplate2.js.map +0 -1
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
import React, { useState, useCallback, useRef, useEffect } from 'react';
|
|
2
|
+
import { Editor } from '@monaco-editor/react';
|
|
3
|
+
import { BsFileText } from '@react-icons/all-files/bs/BsFileText.js';
|
|
4
|
+
import { BsFolder } from '@react-icons/all-files/bs/BsFolder.js';
|
|
5
|
+
import { BsChevronRight } from '@react-icons/all-files/bs/BsChevronRight.js';
|
|
6
|
+
import { BsChevronDown } from '@react-icons/all-files/bs/BsChevronDown.js';
|
|
7
|
+
|
|
8
|
+
interface LiveCodeEditorProps {
|
|
9
|
+
files?: Record<string, string>;
|
|
10
|
+
className?: string;
|
|
11
|
+
onCopyToClipboard?: (text: string) => void;
|
|
12
|
+
onFileUpdate?: (filePath: string, content: string) => Promise<void>;
|
|
13
|
+
readOnly?: boolean;
|
|
14
|
+
autoSave?: boolean;
|
|
15
|
+
debounceMs?: number;
|
|
16
|
+
showFileExplorer?: boolean;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface FileNode {
|
|
20
|
+
name: string;
|
|
21
|
+
type: 'file' | 'folder';
|
|
22
|
+
children?: FileNode[];
|
|
23
|
+
path: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// File Explorer Component
|
|
27
|
+
const FileExplorer: React.FC<{
|
|
28
|
+
files: Record<string, string>;
|
|
29
|
+
currentFile: string;
|
|
30
|
+
onFileSelect: (filePath: string) => void;
|
|
31
|
+
}> = ({ files, currentFile, onFileSelect }) => {
|
|
32
|
+
// Simple file list without folder structure
|
|
33
|
+
const fileList = Object.keys(files);
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<div className="w-48 bg-gray-50 border-l border-gray-200 flex flex-col">
|
|
37
|
+
<div className="p-3 border-b border-gray-200 bg-white">
|
|
38
|
+
<h3 className="text-sm font-semibold text-gray-700">Files</h3>
|
|
39
|
+
</div>
|
|
40
|
+
<div className="flex-1 overflow-y-auto">
|
|
41
|
+
{fileList.map((filePath) => {
|
|
42
|
+
const fileName = filePath.split('/').pop() || filePath;
|
|
43
|
+
const isSelected = currentFile === filePath;
|
|
44
|
+
|
|
45
|
+
return (
|
|
46
|
+
<div
|
|
47
|
+
key={filePath}
|
|
48
|
+
className={`flex items-center py-2 px-3 cursor-pointer hover:bg-gray-100 ${
|
|
49
|
+
isSelected ? 'bg-blue-50 text-blue-600' : 'text-gray-700'
|
|
50
|
+
}`}
|
|
51
|
+
onClick={() => onFileSelect(filePath)}
|
|
52
|
+
>
|
|
53
|
+
<BsFileText className="w-4 h-4 mr-2 text-gray-500" />
|
|
54
|
+
<span className="text-sm">{fileName}</span>
|
|
55
|
+
</div>
|
|
56
|
+
);
|
|
57
|
+
})}
|
|
58
|
+
</div>
|
|
59
|
+
</div>
|
|
60
|
+
);
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export const LiveCodeEditor: React.FC<LiveCodeEditorProps> = ({
|
|
64
|
+
files = {},
|
|
65
|
+
className = '',
|
|
66
|
+
onCopyToClipboard,
|
|
67
|
+
onFileUpdate,
|
|
68
|
+
readOnly = false,
|
|
69
|
+
autoSave = true,
|
|
70
|
+
debounceMs = 500,
|
|
71
|
+
showFileExplorer = true,
|
|
72
|
+
}) => {
|
|
73
|
+
const [currentFile, setCurrentFile] = useState<string>(Object.keys(files)[0] || '');
|
|
74
|
+
const [fileContent, setFileContent] = useState<string>(files[currentFile] || '');
|
|
75
|
+
const editorRef = useRef<any>(null);
|
|
76
|
+
const timeoutRef = useRef<NodeJS.Timeout | null>(null);
|
|
77
|
+
|
|
78
|
+
// Update file content when files prop changes
|
|
79
|
+
useEffect(() => {
|
|
80
|
+
if (files && Object.keys(files).length > 0) {
|
|
81
|
+
const firstFile = Object.keys(files)[0];
|
|
82
|
+
setCurrentFile(firstFile);
|
|
83
|
+
setFileContent(files[firstFile] || '');
|
|
84
|
+
}
|
|
85
|
+
}, [files]);
|
|
86
|
+
|
|
87
|
+
const handleEditorDidMount = useCallback(
|
|
88
|
+
(editor: any, monaco: any) => {
|
|
89
|
+
editorRef.current = editor;
|
|
90
|
+
|
|
91
|
+
// Configure editor options
|
|
92
|
+
editor.updateOptions({
|
|
93
|
+
readOnly,
|
|
94
|
+
minimap: { enabled: false },
|
|
95
|
+
scrollBeyondLastLine: false,
|
|
96
|
+
wordWrap: 'on',
|
|
97
|
+
lineNumbers: 'on',
|
|
98
|
+
folding: true,
|
|
99
|
+
lineDecorationsWidth: 0,
|
|
100
|
+
lineNumbersMinChars: 0,
|
|
101
|
+
renderLineHighlight: 'none',
|
|
102
|
+
cursorStyle: 'line',
|
|
103
|
+
cursorWidth: 1,
|
|
104
|
+
fontSize: 14,
|
|
105
|
+
fontFamily: "'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, 'Courier New', monospace",
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
// Add keyboard shortcuts
|
|
109
|
+
editor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyC, () => {
|
|
110
|
+
const selection = editor.getSelection();
|
|
111
|
+
const selectedText = editor.getModel()?.getValueInRange(selection) || '';
|
|
112
|
+
if (selectedText && onCopyToClipboard) {
|
|
113
|
+
onCopyToClipboard(selectedText);
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
},
|
|
117
|
+
[readOnly, onCopyToClipboard],
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
const handleEditorChange = useCallback(
|
|
121
|
+
(value: string | undefined) => {
|
|
122
|
+
if (value !== undefined) {
|
|
123
|
+
setFileContent(value);
|
|
124
|
+
|
|
125
|
+
// Debounced auto-save
|
|
126
|
+
if (autoSave && onFileUpdate && currentFile) {
|
|
127
|
+
if (timeoutRef.current) {
|
|
128
|
+
clearTimeout(timeoutRef.current);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
timeoutRef.current = setTimeout(() => {
|
|
132
|
+
onFileUpdate(currentFile, value);
|
|
133
|
+
}, debounceMs);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
[autoSave, onFileUpdate, currentFile, debounceMs],
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
const getLanguageFromFileName = (fileName: string): string => {
|
|
141
|
+
const extension = fileName.split('.').pop()?.toLowerCase();
|
|
142
|
+
const languageMap: Record<string, string> = {
|
|
143
|
+
js: 'javascript',
|
|
144
|
+
jsx: 'javascript',
|
|
145
|
+
ts: 'typescript',
|
|
146
|
+
tsx: 'typescript',
|
|
147
|
+
py: 'python',
|
|
148
|
+
java: 'java',
|
|
149
|
+
cpp: 'cpp',
|
|
150
|
+
c: 'c',
|
|
151
|
+
cs: 'csharp',
|
|
152
|
+
php: 'php',
|
|
153
|
+
rb: 'ruby',
|
|
154
|
+
go: 'go',
|
|
155
|
+
rs: 'rust',
|
|
156
|
+
html: 'html',
|
|
157
|
+
css: 'css',
|
|
158
|
+
scss: 'scss',
|
|
159
|
+
sass: 'sass',
|
|
160
|
+
less: 'less',
|
|
161
|
+
json: 'json',
|
|
162
|
+
xml: 'xml',
|
|
163
|
+
yaml: 'yaml',
|
|
164
|
+
yml: 'yaml',
|
|
165
|
+
md: 'markdown',
|
|
166
|
+
sql: 'sql',
|
|
167
|
+
sh: 'shell',
|
|
168
|
+
bash: 'shell',
|
|
169
|
+
dockerfile: 'dockerfile',
|
|
170
|
+
};
|
|
171
|
+
return languageMap[extension || ''] || 'plaintext';
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
// Cleanup timeout on unmount
|
|
175
|
+
useEffect(() => {
|
|
176
|
+
return () => {
|
|
177
|
+
if (timeoutRef.current) {
|
|
178
|
+
clearTimeout(timeoutRef.current);
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
}, []);
|
|
182
|
+
|
|
183
|
+
const handleFileSelect = useCallback(
|
|
184
|
+
(filePath: string) => {
|
|
185
|
+
setCurrentFile(filePath);
|
|
186
|
+
setFileContent(files[filePath] || '');
|
|
187
|
+
},
|
|
188
|
+
[files],
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
return (
|
|
192
|
+
<div className={`flex h-full w-full ${className}`}>
|
|
193
|
+
{/* Editor Area - Left Side */}
|
|
194
|
+
<div className="flex-1 flex flex-col">
|
|
195
|
+
{/* File Name Header */}
|
|
196
|
+
<div className="flex items-center justify-between px-4 py-2 bg-gray-100 border-b border-gray-200">
|
|
197
|
+
<div className="flex items-center">
|
|
198
|
+
<BsFileText className="w-4 h-4 mr-2 text-gray-500" />
|
|
199
|
+
<span className="text-sm font-medium text-gray-700">
|
|
200
|
+
{currentFile.split('/').pop() || currentFile}
|
|
201
|
+
</span>
|
|
202
|
+
</div>
|
|
203
|
+
<div className="flex items-center space-x-2">
|
|
204
|
+
<button className="text-gray-400 hover:text-gray-600">
|
|
205
|
+
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
206
|
+
<path
|
|
207
|
+
strokeLinecap="round"
|
|
208
|
+
strokeLinejoin="round"
|
|
209
|
+
strokeWidth={2}
|
|
210
|
+
d="M6 18L18 6M6 6l12 12"
|
|
211
|
+
/>
|
|
212
|
+
</svg>
|
|
213
|
+
</button>
|
|
214
|
+
</div>
|
|
215
|
+
</div>
|
|
216
|
+
|
|
217
|
+
{/* Monaco Editor */}
|
|
218
|
+
<div className="flex-1" style={{ height: '100%', minHeight: '400px' }}>
|
|
219
|
+
<Editor
|
|
220
|
+
height="100%"
|
|
221
|
+
language={getLanguageFromFileName(currentFile)}
|
|
222
|
+
value={fileContent}
|
|
223
|
+
onMount={handleEditorDidMount}
|
|
224
|
+
onChange={handleEditorChange}
|
|
225
|
+
options={{
|
|
226
|
+
readOnly,
|
|
227
|
+
minimap: { enabled: false },
|
|
228
|
+
scrollBeyondLastLine: true,
|
|
229
|
+
wordWrap: 'on',
|
|
230
|
+
lineNumbers: 'on',
|
|
231
|
+
folding: true,
|
|
232
|
+
lineDecorationsWidth: 0,
|
|
233
|
+
lineNumbersMinChars: 0,
|
|
234
|
+
renderLineHighlight: 'none',
|
|
235
|
+
cursorStyle: 'line',
|
|
236
|
+
cursorWidth: 1,
|
|
237
|
+
fontSize: 14,
|
|
238
|
+
fontFamily:
|
|
239
|
+
"'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, 'Courier New', monospace",
|
|
240
|
+
scrollbar: {
|
|
241
|
+
vertical: 'auto',
|
|
242
|
+
horizontal: 'auto',
|
|
243
|
+
verticalScrollbarSize: 8,
|
|
244
|
+
horizontalScrollbarSize: 8,
|
|
245
|
+
},
|
|
246
|
+
}}
|
|
247
|
+
/>
|
|
248
|
+
</div>
|
|
249
|
+
</div>
|
|
250
|
+
|
|
251
|
+
{/* File Explorer - Right Side */}
|
|
252
|
+
{showFileExplorer && Object.keys(files).length > 0 && (
|
|
253
|
+
<FileExplorer files={files} currentFile={currentFile} onFileSelect={handleFileSelect} />
|
|
254
|
+
)}
|
|
255
|
+
</div>
|
|
256
|
+
);
|
|
257
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { Fill } from '@common-stack/components-pro';
|
|
3
|
+
import { MessengerSlotFillNameEnum } from '../../enums';
|
|
4
|
+
import { RightSidebarFillComponent } from '../filler-components/RightSiderBar';
|
|
5
|
+
|
|
6
|
+
type RightSidebarProps = {
|
|
7
|
+
channelId: string;
|
|
8
|
+
detailSidebarOptions: {
|
|
9
|
+
isMobileView: boolean;
|
|
10
|
+
isSmallTabletView: boolean;
|
|
11
|
+
isTabletView: boolean;
|
|
12
|
+
isDesktopView: boolean;
|
|
13
|
+
isLargeDesktopView: boolean;
|
|
14
|
+
isSmallScreen: boolean;
|
|
15
|
+
[key: string]: any;
|
|
16
|
+
};
|
|
17
|
+
windowWidth: number;
|
|
18
|
+
windowHeight: number;
|
|
19
|
+
activeTab?: string;
|
|
20
|
+
selectedPost?: any;
|
|
21
|
+
messages?: any[];
|
|
22
|
+
setIsLoading?: (isLoading: boolean) => void;
|
|
23
|
+
isLoading?: boolean;
|
|
24
|
+
[key: string]: any;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export const RightSidebarFiller = (props: any) => {
|
|
28
|
+
return <Fill {...props} name={MessengerSlotFillNameEnum.INBOX_WITH_AI_RIGHT_SIDEBAR} />;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export const RightSidebarFill = () => {
|
|
32
|
+
return (
|
|
33
|
+
<RightSidebarFiller>
|
|
34
|
+
{(props: RightSidebarProps) => {
|
|
35
|
+
return <RightSidebarFillComponent {...props} />;
|
|
36
|
+
}}
|
|
37
|
+
</RightSidebarFiller>
|
|
38
|
+
);
|
|
39
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { cn } from '../../utils/utils';
|
|
3
|
+
|
|
4
|
+
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
5
|
+
variant?: 'default' | 'outline' | 'ghost' | 'link';
|
|
6
|
+
size?: 'default' | 'sm' | 'lg';
|
|
7
|
+
children: React.ReactNode;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
|
11
|
+
({ className, variant = 'default', size = 'default', ...props }, ref) => {
|
|
12
|
+
const baseClasses =
|
|
13
|
+
'inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none ring-offset-background';
|
|
14
|
+
|
|
15
|
+
const variants = {
|
|
16
|
+
default: 'bg-primary text-primary-foreground hover:bg-primary/90',
|
|
17
|
+
outline: 'border border-input hover:bg-accent hover:text-accent-foreground',
|
|
18
|
+
ghost: 'hover:bg-accent hover:text-accent-foreground',
|
|
19
|
+
link: 'underline-offset-4 hover:underline text-primary',
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const sizes = {
|
|
23
|
+
default: 'h-10 py-2 px-4',
|
|
24
|
+
sm: 'h-9 px-3 rounded-md',
|
|
25
|
+
lg: 'h-11 px-8 rounded-md',
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
return <button className={cn(baseClasses, variants[variant], sizes[size], className)} ref={ref} {...props} />;
|
|
29
|
+
},
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
Button.displayName = 'Button';
|
|
@@ -845,6 +845,8 @@ const MessagesComponent = React.memo((props: any) => {
|
|
|
845
845
|
const [isLoadingOlder, setIsLoadingOlder] = React.useState(false);
|
|
846
846
|
const isLoadingOlderRef = useRef(false);
|
|
847
847
|
const scrollTimeoutRef = useRef(null);
|
|
848
|
+
const shouldAutoScrollRef = useRef(true);
|
|
849
|
+
const hasInitializedRef = useRef(false);
|
|
848
850
|
|
|
849
851
|
const auth = useSelector(userSelector);
|
|
850
852
|
const { startUpload } = useUploadFiles();
|
|
@@ -866,9 +868,21 @@ const MessagesComponent = React.memo((props: any) => {
|
|
|
866
868
|
}
|
|
867
869
|
}, []);
|
|
868
870
|
|
|
869
|
-
// Auto-scroll
|
|
871
|
+
// Auto-scroll rules:
|
|
872
|
+
// - Initial load: once messages arrive the first time
|
|
873
|
+
// - When user is at bottom and new messages arrive
|
|
874
|
+
// - When we explicitly set shouldAutoScrollRef (e.g., on send)
|
|
870
875
|
useEffect(() => {
|
|
871
|
-
if (
|
|
876
|
+
if (isLoadingOlderRef.current) return;
|
|
877
|
+
|
|
878
|
+
// Initial load: first time messages appear
|
|
879
|
+
if (!hasInitializedRef.current && messages.length > 0) {
|
|
880
|
+
hasInitializedRef.current = true;
|
|
881
|
+
const timer = setTimeout(() => scrollToBottom(), 100);
|
|
882
|
+
return () => clearTimeout(timer);
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
if (shouldAutoScrollRef.current) {
|
|
872
886
|
const timer = setTimeout(() => scrollToBottom(), 100);
|
|
873
887
|
return () => clearTimeout(timer);
|
|
874
888
|
}
|
|
@@ -996,6 +1010,12 @@ const MessagesComponent = React.memo((props: any) => {
|
|
|
996
1010
|
const isAtTop = Math.ceil(scrollTop) <= 25;
|
|
997
1011
|
const hasMoreMessages = totalCount > messages.length;
|
|
998
1012
|
|
|
1013
|
+
// Track bottom proximity to decide future auto-scroll behavior
|
|
1014
|
+
const distanceFromBottom = scrollHeight - (scrollTop + clientHeight);
|
|
1015
|
+
const isAtBottom = distanceFromBottom <= 30;
|
|
1016
|
+
// Only auto-scroll for future incoming messages if user is at bottom
|
|
1017
|
+
shouldAutoScrollRef.current = isAtBottom;
|
|
1018
|
+
|
|
999
1019
|
// Additional Firefox-specific check
|
|
1000
1020
|
const isFirefox = navigator.userAgent.includes('Firefox');
|
|
1001
1021
|
const firefoxAdjustedTop = isFirefox ? Math.round(scrollTop) <= 30 : isAtTop;
|
|
@@ -1028,6 +1048,9 @@ const MessagesComponent = React.memo((props: any) => {
|
|
|
1028
1048
|
if (!channelId) return;
|
|
1029
1049
|
|
|
1030
1050
|
try {
|
|
1051
|
+
// Ensure we auto-scroll when sending a new message
|
|
1052
|
+
shouldAutoScrollRef.current = true;
|
|
1053
|
+
setTimeout(() => scrollToBottom(), 0);
|
|
1031
1054
|
const postId = objectId();
|
|
1032
1055
|
const currentDate = new Date();
|
|
1033
1056
|
|
|
@@ -1178,7 +1201,7 @@ const MessagesComponent = React.memo((props: any) => {
|
|
|
1178
1201
|
console.error('Error sending message:', error);
|
|
1179
1202
|
}
|
|
1180
1203
|
},
|
|
1181
|
-
[channelId, auth, startUpload, sendMsg],
|
|
1204
|
+
[channelId, auth, startUpload, sendMsg, scrollToBottom],
|
|
1182
1205
|
);
|
|
1183
1206
|
|
|
1184
1207
|
// Show loading spinner for initial load
|
|
@@ -3,7 +3,9 @@ import { useNavigate } from '@remix-run/react';
|
|
|
3
3
|
import { RoomType } from 'common';
|
|
4
4
|
import { InputComponent } from '../components/InboxMessage';
|
|
5
5
|
import { objectId } from '@messenger-box/core';
|
|
6
|
-
import { useAddChannelMutation, useSendMessagesMutation } from 'common/graphql';
|
|
6
|
+
import { useAddChannelMutation, useSendMessagesMutation, useCreateChannelWithProjectIdMutation } from 'common/graphql';
|
|
7
|
+
import { ModelConfigPanel } from '../components/ModelConfigPanel';
|
|
8
|
+
import { usePersistentModelConfig } from '../hooks/usePersistentModelConfig';
|
|
7
9
|
|
|
8
10
|
const TailwindOverlaySpinner = React.memo(() => (
|
|
9
11
|
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-30">
|
|
@@ -12,10 +14,14 @@ const TailwindOverlaySpinner = React.memo(() => (
|
|
|
12
14
|
));
|
|
13
15
|
|
|
14
16
|
const AiLandingInput: React.FC = () => {
|
|
17
|
+
const [createChannelWithProjectId] = useCreateChannelWithProjectIdMutation();
|
|
15
18
|
const [addChannel] = useAddChannelMutation();
|
|
16
19
|
const [sendMessage] = useSendMessagesMutation();
|
|
17
20
|
const navigate = useNavigate();
|
|
18
21
|
const [isCreatingChannel, setIsCreatingChannel] = React.useState(false);
|
|
22
|
+
const { modelConfig, updateModelConfig, getValidatedConfig, hasApiKey } = usePersistentModelConfig();
|
|
23
|
+
// const [showModelConfig, setShowModelConfig] = React.useState(!hasApiKey);
|
|
24
|
+
const [showModelConfig, setShowModelConfig] = React.useState(true);
|
|
19
25
|
|
|
20
26
|
return (
|
|
21
27
|
<div className="flex items-center justify-center min-h-screen bg-gray-50">
|
|
@@ -25,38 +31,55 @@ const AiLandingInput: React.FC = () => {
|
|
|
25
31
|
<h3 className="text-xl font-semibold text-gray-700 mb-2">What would you like to build?</h3>
|
|
26
32
|
<p className="text-gray-500">Describe your idea and I'll help you create it step by step.</p>
|
|
27
33
|
</div>
|
|
34
|
+
<div className="mb-0">
|
|
35
|
+
<div className="p-3 bg-gray-50 rounded-lg border">
|
|
36
|
+
<div className="mb-4">
|
|
37
|
+
<h3 className="text-sm font-medium text-gray-900 mb-2">Configuration</h3>
|
|
38
|
+
<p className="text-xs text-gray-600 mb-3">
|
|
39
|
+
Choose your AI model, template, and provide your API key before creating your
|
|
40
|
+
project.
|
|
41
|
+
</p>
|
|
42
|
+
</div>
|
|
43
|
+
<ModelConfigPanel
|
|
44
|
+
config={modelConfig}
|
|
45
|
+
onConfigChange={updateModelConfig}
|
|
46
|
+
isVisible={showModelConfig}
|
|
47
|
+
onToggleVisibility={() => setShowModelConfig(!showModelConfig)}
|
|
48
|
+
showTemplate={true}
|
|
49
|
+
/>
|
|
50
|
+
{!hasApiKey && (
|
|
51
|
+
<div className="mt-2 text-xs text-amber-600">
|
|
52
|
+
⚠️ Please provide an API key to create a projects
|
|
53
|
+
</div>
|
|
54
|
+
)}
|
|
55
|
+
</div>
|
|
56
|
+
</div>
|
|
28
57
|
<InputComponent
|
|
29
58
|
handleSend={async (message: string, files: File[]) => {
|
|
59
|
+
const validated = getValidatedConfig();
|
|
60
|
+
if (!validated && !hasApiKey) {
|
|
61
|
+
setShowModelConfig(true);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
30
64
|
console.log('Message sent without channel:', message, files);
|
|
31
65
|
setIsCreatingChannel(true);
|
|
32
66
|
const id = objectId();
|
|
33
|
-
|
|
67
|
+
createChannelWithProjectId({
|
|
34
68
|
variables: {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
69
|
+
projectId: id,
|
|
70
|
+
channelInput: {
|
|
71
|
+
content: message,
|
|
72
|
+
modelConfig: modelConfig,
|
|
73
|
+
},
|
|
38
74
|
},
|
|
39
75
|
onCompleted: (data: any) => {
|
|
40
76
|
console.log('Channel created:', data);
|
|
41
|
-
if (!data.
|
|
77
|
+
if (!data.createChannelWithProjectId) {
|
|
42
78
|
setIsCreatingChannel(false);
|
|
43
79
|
return;
|
|
44
80
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
variables: {
|
|
48
|
-
channelId: createdId,
|
|
49
|
-
content: message,
|
|
50
|
-
},
|
|
51
|
-
onCompleted: () => {
|
|
52
|
-
navigate(`/ai-messenger/app?id=${createdId}`, { replace: true });
|
|
53
|
-
setIsCreatingChannel(false);
|
|
54
|
-
},
|
|
55
|
-
onError: (error: any) => {
|
|
56
|
-
console.error('Error sending message:', error);
|
|
57
|
-
setIsCreatingChannel(false);
|
|
58
|
-
},
|
|
59
|
-
});
|
|
81
|
+
navigate(`/ai-messenger/app?id=${id}`, { replace: true });
|
|
82
|
+
setIsCreatingChannel(false);
|
|
60
83
|
},
|
|
61
84
|
onError: (error: any) => {
|
|
62
85
|
console.error('Error creating channel:', error);
|
|
@@ -66,7 +89,7 @@ const AiLandingInput: React.FC = () => {
|
|
|
66
89
|
}}
|
|
67
90
|
placeholder="Type your message here..."
|
|
68
91
|
/>
|
|
69
|
-
<div className="mt-2">
|
|
92
|
+
{/* <div className="mt-2">
|
|
70
93
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
|
71
94
|
<div className="space-y-2">
|
|
72
95
|
<div className="relative">
|
|
@@ -155,6 +178,9 @@ const AiLandingInput: React.FC = () => {
|
|
|
155
178
|
</div>
|
|
156
179
|
</div>
|
|
157
180
|
</div>
|
|
181
|
+
</div> */}
|
|
182
|
+
<div className="text-center text-sm text-gray-400">
|
|
183
|
+
Each project gets its own workspace where you can iterate and refine your ideas.
|
|
158
184
|
</div>
|
|
159
185
|
</div>
|
|
160
186
|
</div>
|
|
@@ -1,47 +1,10 @@
|
|
|
1
1
|
import React, { useMemo, useCallback } from 'react';
|
|
2
|
-
import { useParams, useLocation } from '@remix-run/react';
|
|
3
|
-
import {
|
|
4
|
-
useGetChannelsByUserQuery,
|
|
5
|
-
useGetChannelsByUserWithLastMessageQuery,
|
|
6
|
-
useMessagesQuery,
|
|
7
|
-
useViewChannelDetailQuery,
|
|
8
|
-
} from 'common/graphql';
|
|
9
|
-
import { RoomType } from 'common';
|
|
10
|
-
import { config } from '../config';
|
|
11
|
-
import Inbox from '../templates/InboxWithAi';
|
|
12
|
-
import { InputComponent } from '../components/InboxMessage';
|
|
2
|
+
import { useParams, useLocation, useOutletContext } from '@remix-run/react';
|
|
13
3
|
import { AIAgent } from '../components/AIAgent';
|
|
14
4
|
import { useSelector, shallowEqual } from 'react-redux';
|
|
15
5
|
import { Store, userSelector } from '@adminide-stack/user-auth0-client';
|
|
16
6
|
import { IUserState } from '@adminide-stack/core';
|
|
17
7
|
|
|
18
|
-
const { MESSAGES_PER_PAGE } = config;
|
|
19
|
-
|
|
20
|
-
// Enhanced query parameters generator with better typing and flexibility
|
|
21
|
-
export const queryParamsGenerator = (params: {
|
|
22
|
-
role?: string;
|
|
23
|
-
criteria?: Record<string, any>;
|
|
24
|
-
supportServices?: boolean;
|
|
25
|
-
orgName?: string;
|
|
26
|
-
}) => ({
|
|
27
|
-
variable1: {
|
|
28
|
-
role: params.role,
|
|
29
|
-
criteria: {
|
|
30
|
-
...params.criteria,
|
|
31
|
-
...(params.orgName && { orgName: params.orgName }),
|
|
32
|
-
},
|
|
33
|
-
supportServices: params.supportServices ? true : false,
|
|
34
|
-
supportServiceCriteria: params.supportServices
|
|
35
|
-
? {
|
|
36
|
-
type: RoomType.Service,
|
|
37
|
-
}
|
|
38
|
-
: undefined,
|
|
39
|
-
orderBy: {
|
|
40
|
-
lastPostAt: 'desc',
|
|
41
|
-
},
|
|
42
|
-
},
|
|
43
|
-
});
|
|
44
|
-
|
|
45
8
|
interface InboxWithAiLoaderOutletProps {
|
|
46
9
|
channelFilters?: Record<string, any>;
|
|
47
10
|
channelRole?: string;
|
|
@@ -52,14 +15,27 @@ interface InboxWithAiLoaderOutletProps {
|
|
|
52
15
|
}
|
|
53
16
|
|
|
54
17
|
const InboxWithAiLoaderOutlet = (props: InboxWithAiLoaderOutletProps) => {
|
|
55
|
-
const { channelFilters: channelFilterProp, channelRole: channelRoleProp, supportServices, pathPrefix } = props;
|
|
56
|
-
const { orgName, channelRole: channelRoleParam } = useParams();
|
|
57
18
|
const location = useLocation();
|
|
19
|
+
const { messages, setMessages, selectedPost, setSelectedPost, setIsLoading, isLoading } = useOutletContext() as any;
|
|
58
20
|
const urlParams = location?.search ? new URLSearchParams(location.search) : null;
|
|
59
21
|
const channelId = urlParams?.get('id');
|
|
60
22
|
const user: any = useSelector<Store.Auth, IUserState>(userSelector, shallowEqual);
|
|
61
23
|
|
|
62
|
-
return
|
|
24
|
+
return (
|
|
25
|
+
<AIAgent
|
|
26
|
+
channelId={channelId}
|
|
27
|
+
placeholder="Ask me anything..."
|
|
28
|
+
className="h-full"
|
|
29
|
+
currentUser={user}
|
|
30
|
+
messages={messages}
|
|
31
|
+
setMessages={setMessages}
|
|
32
|
+
selectedPost={selectedPost}
|
|
33
|
+
setSelectedPost={setSelectedPost}
|
|
34
|
+
setIsLoading={setIsLoading}
|
|
35
|
+
isLoading={isLoading}
|
|
36
|
+
{...props}
|
|
37
|
+
/>
|
|
38
|
+
);
|
|
63
39
|
};
|
|
64
40
|
|
|
65
41
|
// Display name for debugging
|
package/src/container/index.ts
CHANGED
|
@@ -5,9 +5,13 @@ import ThreadMessages from './ThreadMessages';
|
|
|
5
5
|
import ServiceInbox from './ServiceInbox';
|
|
6
6
|
import { ThreadsInbox } from './ThreadsInbox';
|
|
7
7
|
import { ThreadMessagesInbox } from './ThreadMessagesInbox';
|
|
8
|
-
import AiInboxWithLoader from './AiInboxWithLoader';
|
|
9
|
-
import AiInbox from './AiInbox';
|
|
10
|
-
import InboxTemplate1 from './InboxTemplate1';
|
|
8
|
+
////import AiInboxWithLoader from './AiInboxWithLoader';
|
|
9
|
+
//import AiInbox from './AiInbox';
|
|
10
|
+
//import InboxTemplate1 from './InboxTemplate1';
|
|
11
|
+
import InboxWithAiLoader from './InboxWithAiLoader';
|
|
12
|
+
import InboxAiMessagesLoader from './InboxAiMessagesLoader';
|
|
13
|
+
import InboxContainer from './InboxContainer';
|
|
14
|
+
import AiLandingInput from './AiLandingInput';
|
|
11
15
|
|
|
12
16
|
export {
|
|
13
17
|
Inbox,
|
|
@@ -17,7 +21,11 @@ export {
|
|
|
17
21
|
ThreadMessages,
|
|
18
22
|
ServiceInbox,
|
|
19
23
|
InboxWithLoader,
|
|
20
|
-
AiInboxWithLoader,
|
|
21
|
-
AiInbox,
|
|
22
|
-
InboxTemplate1,
|
|
24
|
+
// AiInboxWithLoader,
|
|
25
|
+
// AiInbox,
|
|
26
|
+
// InboxTemplate1,
|
|
27
|
+
InboxWithAiLoader,
|
|
28
|
+
InboxAiMessagesLoader,
|
|
29
|
+
InboxContainer,
|
|
30
|
+
AiLandingInput,
|
|
23
31
|
};
|