Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 0205c72

Browse files
committed
[Feat]: Add chat component
1 parent bf9f269 commit 0205c72

File tree

8 files changed

+449
-313
lines changed

8 files changed

+449
-313
lines changed

‎client/packages/lowcoder/src/comps/comps/chatComp/chatView.tsx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// client/packages/lowcoder/src/comps/comps/chatComp/chatView.tsx
22
import React from "react";
33
import { ChatCompProps } from "./chatCompTypes";
4-
import { ChatApp } from "./components/ChatWithThreads";
4+
import { ChatApp } from "./components/ChatApp";
55

66
import "@assistant-ui/styles/index.css";
77
import "@assistant-ui/styles/markdown.css";
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { ChatProvider } from "./context/ChatContext";
2+
import { ChatMain } from "./ChatMain";
3+
4+
export function ChatApp() {
5+
return (
6+
<ChatProvider>
7+
<ChatMain />
8+
</ChatProvider>
9+
);
10+
}
Lines changed: 46 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,47 @@
1-
import React, { useState,useEffect } from "react";
1+
import React, { useState } from "react";
22
import {
33
useExternalStoreRuntime,
44
ThreadMessageLike,
55
AppendMessage,
66
AssistantRuntimeProvider,
77
ExternalStoreThreadListAdapter,
88
} from "@assistant-ui/react";
9-
import { useThreadContext, MyMessage, ThreadProvider } from "./context/ThreadContext";
109
import { Thread } from "./assistant-ui/thread";
1110
import { ThreadList } from "./assistant-ui/thread-list";
12-
import { chatStorage, ThreadData as StoredThreadData } from "../utils/chatStorage";
13-
import { useChatStorage } from "../hooks/useChatStorage";
11+
import {
12+
useChatContext,
13+
MyMessage,
14+
ThreadData,
15+
RegularThreadData,
16+
ArchivedThreadData
17+
} from "./context/ChatContext";
1418
import styled from "styled-components";
1519

16-
17-
18-
1920
const ChatContainer = styled.div`
2021
display: flex;
2122
height: 500px;
2223
2324
.aui-thread-list-root {
2425
width: 250px;
25-
background-color: #333;
26+
background-color: #fff;
27+
padding: 10px;
2628
}
2729
2830
.aui-thread-root {
2931
flex: 1;
30-
background-color: #f0f0f0;
32+
background-color: #f9fafb;
3133
}
3234
33-
`;
34-
35-
// Define thread data interfaces to match ExternalStoreThreadData requirements
36-
interface RegularThreadData {
37-
threadId: string;
38-
status: "regular";
39-
title: string;
40-
}
35+
.aui-thread-list-item {
36+
cursor: pointer;
37+
transition: background-color 0.2s ease;
4138
42-
interface ArchivedThreadData {
43-
threadId: string;
44-
status: "archived";
45-
title: string;
46-
}
47-
48-
type ThreadData = RegularThreadData | ArchivedThreadData;
39+
&[data-active="true"] {
40+
background-color: #dbeafe;
41+
border: 1px solid #bfdbfe;
42+
}
43+
}
44+
`;
4945

5046
const generateId = () => Math.random().toString(36).substr(2, 9);
5147

@@ -59,22 +55,14 @@ const callYourAPI = async (text: string) => {
5955
};
6056
};
6157

62-
function ChatWithThreads() {
63-
const { currentThreadId, setCurrentThreadId, threads, setThreads } =
64-
useThreadContext();
58+
export function ChatMain() {
59+
const { state, actions } = useChatContext();
6560
const [isRunning, setIsRunning] = useState(false);
66-
const [threadList, setThreadList] = useState<ThreadData[]>([
67-
{ threadId: "default", status: "regular", title: "New Chat" } as RegularThreadData,
68-
]);
69-
const { isInitialized } = useChatStorage({
70-
threadList,
71-
threads,
72-
setThreadList,
73-
setThreads,
74-
setCurrentThreadId,
75-
});
61+
62+
console.log("STATE", state);
63+
7664
// Get messages for current thread
77-
const currentMessages = threads.get(currentThreadId)||[];
65+
const currentMessages = actions.getCurrentMessages();
7866

7967
// Convert custom format to ThreadMessageLike
8068
const convertMessage = (message: MyMessage): ThreadMessageLike => ({
@@ -99,8 +87,7 @@ function ChatWithThreads() {
9987
};
10088

10189
// Update current thread with new user message
102-
const updatedMessages = [...currentMessages, userMessage];
103-
setThreads(prev => new Map(prev).set(currentThreadId, updatedMessages));
90+
await actions.addMessage(state.currentThreadId, userMessage);
10491
setIsRunning(true);
10592

10693
try {
@@ -115,8 +102,7 @@ function ChatWithThreads() {
115102
};
116103

117104
// Update current thread with assistant response
118-
const finalMessages = [...updatedMessages, assistantMessage];
119-
setThreads(prev => new Map(prev).set(currentThreadId, finalMessages));
105+
await actions.addMessage(state.currentThreadId, assistantMessage);
120106
} catch (error) {
121107
// Handle errors gracefully
122108
const errorMessage: MyMessage = {
@@ -126,8 +112,7 @@ function ChatWithThreads() {
126112
timestamp: Date.now(),
127113
};
128114

129-
const finalMessages = [...updatedMessages, errorMessage];
130-
setThreads(prev => new Map(prev).set(currentThreadId, finalMessages));
115+
await actions.addMessage(state.currentThreadId, errorMessage);
131116
} finally {
132117
setIsRunning(false);
133118
}
@@ -155,7 +140,8 @@ function ChatWithThreads() {
155140
};
156141
newMessages.push(editedMessage);
157142

158-
setThreads(prev => new Map(prev).set(currentThreadId, newMessages));
143+
// Update messages using the new context action
144+
await actions.updateMessages(state.currentThreadId, newMessages);
159145
setIsRunning(true);
160146

161147
try {
@@ -170,7 +156,7 @@ function ChatWithThreads() {
170156
};
171157

172158
newMessages.push(assistantMessage);
173-
setThreads(prev=>newMap(prev).set(currentThreadId, newMessages));
159+
awaitactions.updateMessages(state.currentThreadId, newMessages);
174160
} catch (error) {
175161
// Handle errors gracefully
176162
const errorMessage: MyMessage = {
@@ -181,89 +167,44 @@ function ChatWithThreads() {
181167
};
182168

183169
newMessages.push(errorMessage);
184-
setThreads(prev=>newMap(prev).set(currentThreadId, newMessages));
170+
awaitactions.updateMessages(state.currentThreadId, newMessages);
185171
} finally {
186172
setIsRunning(false);
187173
}
188174
};
189175

190176
// Thread list adapter for managing multiple threads
191177
const threadListAdapter: ExternalStoreThreadListAdapter = {
192-
threadId: currentThreadId,
193-
threads: threadList.filter((t): t is RegularThreadData => t.status === "regular"),
194-
archivedThreads: threadList.filter((t): t is ArchivedThreadData => t.status === "archived"),
178+
threadId: state.currentThreadId,
179+
threads: state.threadList.filter((t): t is RegularThreadData => t.status === "regular"),
180+
archivedThreads: state.threadList.filter((t): t is ArchivedThreadData => t.status === "archived"),
195181

196182
onSwitchToNewThread: async () => {
197-
const newId = `thread-${Date.now()}`;
198-
const newThread: RegularThreadData = {
199-
threadId: newId,
200-
status: "regular",
201-
title: "New Chat",
202-
};
203-
204-
setThreadList((prev) => [...prev, newThread]);
205-
setThreads((prev) => new Map(prev).set(newId, []));
206-
setCurrentThreadId(newId);
207-
208-
// Save new thread to storage
209-
try {
210-
const storedThread: StoredThreadData = {
211-
threadId: newId,
212-
status: "regular",
213-
title: "New Chat",
214-
createdAt: Date.now(),
215-
updatedAt: Date.now(),
216-
};
217-
await chatStorage.saveThread(storedThread);
218-
} catch (error) {
219-
console.error("Failed to save new thread:", error);
220-
}
183+
const threadId = await actions.createThread("New Chat");
184+
actions.setCurrentThread(threadId);
221185
},
222186

223187
onSwitchToThread: (threadId) => {
224-
setCurrentThreadId(threadId);
188+
actions.setCurrentThread(threadId);
225189
},
226190

227-
onRename: (threadId, newTitle) => {
228-
setThreadList((prev) =>
229-
prev.map((t) =>
230-
t.threadId === threadId ? { ...t, title: newTitle } : t,
231-
),
232-
);
191+
onRename: async (threadId, newTitle) => {
192+
await actions.updateThread(threadId, { title: newTitle });
233193
},
234194

235-
onArchive: (threadId) => {
236-
setThreadList((prev) =>
237-
prev.map((t) =>
238-
t.threadId === threadId ? { ...t, status: "archived" } : t,
239-
),
240-
);
195+
onArchive: async (threadId) => {
196+
await actions.updateThread(threadId, { status: "archived" });
241197
},
242198

243199
onDelete: async (threadId) => {
244-
setThreadList((prev) => prev.filter((t) => t.threadId !== threadId));
245-
setThreads((prev) => {
246-
const next = new Map(prev);
247-
next.delete(threadId);
248-
return next;
249-
});
250-
if (currentThreadId === threadId) {
251-
setCurrentThreadId("default");
252-
}
253-
254-
// Delete thread from storage
255-
try {
256-
await chatStorage.deleteThread(threadId);
257-
} catch (error) {
258-
console.error("Failed to delete thread from storage:", error);
259-
}
200+
await actions.deleteThread(threadId);
260201
},
261202
};
262203

263204
const runtime = useExternalStoreRuntime({
264205
messages: currentMessages,
265206
setMessages: (messages) => {
266-
setThreads((prev)=>newMap(prev).set(currentThreadId, messages));
207+
actions.updateMessages(state.currentThreadId, messages);
267208
},
268209
convertMessage,
269210
isRunning,
@@ -274,7 +215,7 @@ function ChatWithThreads() {
274215
},
275216
});
276217

277-
if (!isInitialized) {
218+
if (!state.isInitialized) {
278219
return <div>Loading...</div>;
279220
}
280221

@@ -288,13 +229,3 @@ function ChatWithThreads() {
288229
);
289230
}
290231

291-
// Main App component with proper context wrapping
292-
export function ChatApp() {
293-
return (
294-
<ThreadProvider>
295-
<ChatWithThreads />
296-
</ThreadProvider>
297-
);
298-
}
299-
300-
export { ChatWithThreads };

‎client/packages/lowcoder/src/comps/comps/chatComp/components/assistant-ui/thread-list.tsx‎

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,18 @@ import {
55
} from "@assistant-ui/react";
66
import { PencilIcon, PlusIcon, Trash2Icon } from "lucide-react";
77

8-
import { Button } from "../ui/button";
98
import { TooltipIconButton } from "./tooltip-icon-button";
109
import { useThreadListItemRuntime } from "@assistant-ui/react";
10+
import { Button } from "antd";
11+
12+
import styled from "styled-components";
13+
import { useChatContext } from "../context/ChatContext";
14+
15+
const StyledPrimaryButton = styled(Button)`
16+
padding: 20px;
17+
margin-bottom: 20px;
18+
`;
19+
1120

1221
export const ThreadList: FC = () => {
1322
return (
@@ -21,10 +30,9 @@ export const ThreadList: FC = () => {
2130
const ThreadListNew: FC = () => {
2231
return (
2332
<ThreadListPrimitive.New asChild>
24-
<Button className="aui-thread-list-new" variant="ghost">
25-
<PlusIcon />
33+
<StyledPrimaryButton size="large" type="primary" icon={<PlusIcon />}>
2634
New Thread
27-
</Button>
35+
</StyledPrimaryButton>
2836
</ThreadListPrimitive.New>
2937
);
3038
};
@@ -46,6 +54,7 @@ const ThreadListItem: FC = () => {
4654
};
4755

4856
const ThreadListItemTitle: FC = () => {
57+
4958
return (
5059
<p className="aui-thread-list-item-title">
5160
<ThreadListItemPrimitive.Title fallback="New Chat" />

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /