1- import React , { useCallback , useContext , useEffect , useRef } from "react" ;
1+ import React , { useContext } from "react" ;
22import { Section , sectionNames } from "lowcoder-design" ;
33import { UICompBuilder , withDefault } from "../../generators" ;
4- import { NameConfig , NameConfigHidden , withExposingConfigs } from "../../generators/withExposing" ;
5- import { withMethodExposing } from "../../generators/withMethodExposing" ;
6- import { stringExposingStateControl , arrayObjectExposingStateControl } from "comps/controls/codeStateControl" ;
4+ import {
5+ NameConfig ,
6+ NameConfigHidden ,
7+ withExposingConfigs ,
8+ } from "../../generators/withExposing" ;
9+ import { stringExposingStateControl } from "comps/controls/codeStateControl" ;
710import { BoolControl } from "comps/controls/boolControl" ;
8- import { StringControl } from "comps/controls/codeControl" ;
11+ import { StringControl , jsonArrayControl } from "comps/controls/codeControl" ;
912import { AutoHeightControl } from "comps/controls/autoHeightControl" ;
1013import { eventHandlerControl } from "comps/controls/eventHandlerControl" ;
1114import { styleControl } from "comps/controls/styleControl" ;
12- import { AnimationStyle , TextStyle } from "comps/controls/styleControlConstants" ;
15+ import {
16+ AnimationStyle ,
17+ TextStyle ,
18+ } from "comps/controls/styleControlConstants" ;
1319import { hiddenPropertyView } from "comps/utils/propertyUtils" ;
1420import { EditorContext } from "comps/editorState" ;
15- import { trans } from "i18n" ;
1621
17- import { PluvRoomProvider , pluvConfig } from "./store" ;
18- import { yjs } from "@pluv/crdt-yjs" ;
1922import { ChatBoxView } from "./components/ChatBoxView" ;
2023
24+ // ─── Events ──────────────────────────────────────────────────────────────────
25+
2126const ChatEvents = [
22- { label : trans ( "chatBox.messageSent" ) , value : "messageSent" , description : trans ( "chatBox.messageSentDesc" ) } ,
23- { label : trans ( "chatBox.messageReceived" ) , value : "messageReceived" , description : trans ( "chatBox.messageReceivedDesc" ) } ,
24- { label : trans ( "chatBox.roomJoined" ) , value : "roomJoined" , description : trans ( "chatBox.roomJoinedDesc" ) } ,
25- { label : trans ( "chatBox.roomLeft" ) , value : "roomLeft" , description : trans ( "chatBox.roomLeftDesc" ) } ,
2627 {
27- label : "LLM Message Received" ,
28- value : "llmMessageReceived" ,
29- description : "Fired when an AI response arrives in an LLM room" ,
28+ label : "Message Sent" ,
29+ value : "messageSent" ,
30+ description :
31+ "Triggered when the user presses send. Read chatBox.lastSentMessageText to get the message content." ,
32+ } ,
33+ {
34+ label : "Start Typing" ,
35+ value : "startTyping" ,
36+ description :
37+ "Triggered when the user starts typing. Wire this to chatController.startTyping()." ,
38+ } ,
39+ {
40+ label : "Stop Typing" ,
41+ value : "stopTyping" ,
42+ description :
43+ "Triggered when the user stops typing. Wire this to chatController.stopTyping()." ,
3044 } ,
3145] as const ;
3246
47+ // ─── Children map ────────────────────────────────────────────────────────────
48+
3349const childrenMap = {
34- chatName : stringExposingStateControl ( "chatName" , "Chat Room" ) ,
35- userId : stringExposingStateControl ( "userId" , "user_1" ) ,
36- userName : stringExposingStateControl ( "userName" , "User" ) ,
37- applicationId : stringExposingStateControl ( "applicationId" , "lowcoder_app" ) ,
38-
39- // Pluv.io connection settings
40- pluvPublicKey : withDefault ( StringControl , "" ) ,
41- pluvAuthUrl : withDefault ( StringControl , "/api/auth/pluv" ) ,
42-
43- // Room panel
44- allowRoomCreation : withDefault ( BoolControl , true ) ,
45- allowRoomSearch : withDefault ( BoolControl , true ) ,
46- showRoomPanel : withDefault ( BoolControl , true ) ,
47- roomPanelWidth : withDefault ( StringControl , "220px" ) ,
48-
49- // LLM settings
50- systemPrompt : withDefault (
51- StringControl ,
52- "You are a helpful AI assistant. Answer concisely and clearly." ,
53- ) ,
54- llmBotName : withDefault ( StringControl , "AI Assistant" ) ,
50+ chatTitle : stringExposingStateControl ( "chatTitle" , "Chat" ) ,
51+ showHeader : withDefault ( BoolControl , true ) ,
52+
53+ messages : jsonArrayControl ( [ ] ) ,
54+ currentUserId : withDefault ( StringControl , "user_1" ) ,
55+ currentUserName : withDefault ( StringControl , "User" ) ,
56+ typingUsers : jsonArrayControl ( [ ] ) ,
5557
56- // Exposed state
57- llmConversationHistory : arrayObjectExposingStateControl ( "llmConversationHistory ", [ ] ) ,
58+ lastSentMessageText : stringExposingStateControl ( "lastSentMessageText" , "" ) ,
59+ messageText : stringExposingStateControl ( "messageText ", "" ) ,
5860
59- // Layout / style
6061 autoHeight : AutoHeightControl ,
6162 onEvent : eventHandlerControl ( ChatEvents ) ,
6263 style : styleControl ( TextStyle , "style" ) ,
6364 animationStyle : styleControl ( AnimationStyle , "animationStyle" ) ,
6465} ;
6566
67+ // ─── Property panel ──────────────────────────────────────────────────────────
68+
6669const ChatBoxPropertyView = React . memo ( ( props : { children : any } ) => {
6770 const { children } = props ;
6871 const editorMode = useContext ( EditorContext ) . editorModeStatus ;
6972
7073 return (
7174 < >
7275 < Section name = { sectionNames . basic } >
73- { children . chatName . propertyView ( { label : "Chat Name" , tooltip : "Display name for the chat header" } ) }
74- { children . userId . propertyView ( { label : "User ID" , tooltip : "Current user's unique identifier" } ) }
75- { children . userName . propertyView ( { label : "User Name" , tooltip : "Current user's display name" } ) }
76- { children . applicationId . propertyView ( { label : "Application ID" , tooltip : "Scopes rooms to this application" } ) }
77- </ Section >
78-
79- < Section name = "Pluv.io Connection" >
80- { children . pluvPublicKey . propertyView ( {
81- label : "Public Key" ,
82- tooltip : "Pluv.io publishable key (pk_...). Can also be set via VITE_PLUV_PUBLIC_KEY env var." ,
76+ { children . chatTitle . propertyView ( {
77+ label : "Chat Title" ,
78+ tooltip : "Display title shown in the chat header" ,
79+ } ) }
80+ { children . messages . propertyView ( {
81+ label : "Messages" ,
82+ tooltip :
83+ 'Bind to your data query, e.g. {{ loadMessages.data }}. Expected shape: [{ id, text, authorId, authorName, timestamp }]' ,
8384 } ) }
84- { children . pluvAuthUrl . propertyView ( {
85- label : "Auth URL" ,
86- tooltip : "Pluv auth endpoint URL for token exchange (e.g. /api/auth/pluv or http://localhost:3006/api/auth/pluv)" ,
85+ { children . currentUserId . propertyView ( {
86+ label : "Current User ID" ,
87+ tooltip :
88+ "The current user's ID — used to distinguish own vs. other messages. Bind to {{ chatController1.userId }}" ,
89+ } ) }
90+ { children . currentUserName . propertyView ( {
91+ label : "Current User Name" ,
92+ tooltip : "The current user's display name" ,
8793 } ) }
8894 </ Section >
8995
90- < Section name = "Room Settings" >
91- { children . allowRoomCreation . propertyView ( { label : "Allow Room Creation" } ) }
92- { children . allowRoomSearch . propertyView ( { label : "Allow Room Search" } ) }
93- { children . showRoomPanel . propertyView ( { label : "Show Room Panel" } ) }
94- { children . roomPanelWidth . propertyView ( { label : "Panel Width" , tooltip : "e.g. 220px or 25%" } ) }
96+ < Section name = "Real-time" >
97+ { children . typingUsers . propertyView ( {
98+ label : "Typing Users" ,
99+ tooltip :
100+ "Array of users currently typing. Bind to {{ chatController1.typingUsers }}" ,
101+ } ) }
95102 </ Section >
96103
97- < Section name = "AI / LLM Settings" >
98- { children . systemPrompt . propertyView ( {
99- label : "System Prompt" ,
100- tooltip : "Prepended to the conversation history sent to your query. Tells the AI how to behave." ,
101- } ) }
102- { children . llmBotName . propertyView ( {
103- label : "AI Bot Name" ,
104- tooltip : "Display name shown on AI messages in LLM rooms." ,
105- } ) }
104+ < Section name = "Display" >
105+ { children . showHeader . propertyView ( { label : "Show Header" } ) }
106106 </ Section >
107107
108108 { [ "logic" , "both" ] . includes ( editorMode ) && (
@@ -131,55 +131,29 @@ const ChatBoxPropertyView = React.memo((props: { children: any }) => {
131131
132132ChatBoxPropertyView . displayName = "ChatBoxV2PropertyView" ;
133133
134- let ChatBoxV2Tmp = ( function ( ) {
135- return new UICompBuilder ( childrenMap , ( props , dispatch ) => {
136- const onChangeRef = useRef ( props . llmConversationHistory . onChange ) ;
137- useEffect ( ( ) => {
138- onChangeRef . current = props . llmConversationHistory . onChange ;
139- } ) ;
140-
141- const onConversationHistoryChange = useCallback ( ( history : any [ ] ) => {
142- onChangeRef . current ( history ) ;
143- } , [ ] ) ;
144-
145- const appId = props . applicationId . value || "lowcoder_app" ;
146- const userId = props . userId . value || "user_1" ;
147- const userName = props . userName . value || "User" ;
148- const roomName = `chatv2_${ appId } ` ;
149-
150- // Update the module-level config before pluv connects.
151- // publicKey MUST be set here so resolvePluvPublicKey() returns the right
152- // value when PluvRoomProvider opens its WebSocket connection.
153- pluvConfig . userId = userId ;
154- pluvConfig . userName = userName ;
155- pluvConfig . authUrl = props . pluvAuthUrl || "/api/auth/pluv" ;
156- pluvConfig . publicKey = props . pluvPublicKey || "" ;
134+ // ─── Component ───────────────────────────────────────────────────────────────
157135
136+ let ChatBoxV2Tmp = ( function ( ) {
137+ return new UICompBuilder ( childrenMap , ( props ) => {
158138 return (
159- < PluvRoomProvider
160- room = { roomName }
161- initialPresence = { { typing : null } as any }
162- initialStorage = { ( t : any ) => ( {
163- rooms : t . map ( "rooms" , [ ] ) ,
164- members : t . map ( "members" , [ ] ) ,
165- invites : t . map ( "invites" , [ ] ) ,
166- messages : t . map ( "messages" , [ ] ) ,
167- } ) }
168- onAuthorizationFail = { ( error : Error ) => {
169- console . error ( "[PluvChat] Auth failed:" , error ) ;
170- } }
171- >
172- < ChatBoxView
173- { ...props }
174- dispatch = { dispatch }
175- onConversationHistoryChange = { onConversationHistoryChange }
176- systemPrompt = { props . systemPrompt }
177- llmBotName = { props . llmBotName }
178- />
179- </ PluvRoomProvider >
139+ < ChatBoxView
140+ chatTitle = { props . chatTitle }
141+ showHeader = { props . showHeader }
142+ messages = { props . messages }
143+ currentUserId = { props . currentUserId }
144+ currentUserName = { props . currentUserName }
145+ typingUsers = { props . typingUsers }
146+ lastSentMessageText = { props . lastSentMessageText }
147+ messageText = { props . messageText }
148+ style = { props . style }
149+ animationStyle = { props . animationStyle }
150+ onEvent = { props . onEvent }
151+ />
180152 ) ;
181153 } )
182- . setPropertyViewFn ( ( children ) => < ChatBoxPropertyView children = { children } /> )
154+ . setPropertyViewFn ( ( children ) => (
155+ < ChatBoxPropertyView children = { children } />
156+ ) )
183157 . build ( ) ;
184158} ) ( ) ;
185159
@@ -189,28 +163,12 @@ ChatBoxV2Tmp = class extends ChatBoxV2Tmp {
189163 }
190164} ;
191165
192- ChatBoxV2Tmp = withMethodExposing ( ChatBoxV2Tmp , [
193- {
194- method : {
195- name : "setUser" ,
196- description : "Update the current chat user" ,
197- params : [
198- { name : "userId" , type : "string" } ,
199- { name : "userName" , type : "string" } ,
200- ] ,
201- } ,
202- execute : ( comp : any , values : any [ ] ) => {
203- if ( values [ 0 ] ) comp . children . userId . getView ( ) . onChange ( values [ 0 ] ) ;
204- if ( values [ 1 ] ) comp . children . userName . getView ( ) . onChange ( values [ 1 ] ) ;
205- } ,
206- } ,
207- ] ) ;
208-
209166export const ChatBoxV2Comp = withExposingConfigs ( ChatBoxV2Tmp , [
210- new NameConfig ( "chatName" , "Chat display name" ) ,
211- new NameConfig ( "userId" , "Current user ID" ) ,
212- new NameConfig ( "userName" , "Current user name" ) ,
213- new NameConfig ( "applicationId" , "Application scope" ) ,
214- new NameConfig ( "llmConversationHistory" , "Conversation history for the active LLM room (role + content array)" ) ,
167+ new NameConfig ( "chatTitle" , "Chat display title" ) ,
168+ new NameConfig (
169+ "lastSentMessageText" ,
170+ "Text of the last message sent by the user — use in your save query" ,
171+ ) ,
172+ new NameConfig ( "messageText" , "Current text in the message input" ) ,
215173 NameConfigHidden ,
216174] ) ;
0 commit comments