@canmingir/link 1.2.66 → 1.2.67
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/.babelrc +5 -1
- package/bun.lock +127 -2
- package/package.json +2 -1
- package/src/layouts/DrawerLayout/DrawerLayout.jsx +6 -0
- package/src/lib/DevTool/DevTool.jsx +157 -97
- package/src/lib/DevTool/DevToolFrame.jsx +116 -0
- package/src/lib/SidebarChat/ChatDrawer.tsx +1 -0
- package/src/lib/SidebarChat/SessionPopover.tsx +1 -0
- package/src/lib/SidebarChat/SidebarChat.tsx +22 -117
- package/src/lib/SidebarChat/SidebarSessionList.tsx +71 -8
- package/src/stories/DevTool.stories.jsx +336 -0
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
import Box from "@mui/material/Box";
|
|
2
|
+
import CssBaseline from "@mui/material/CssBaseline";
|
|
3
|
+
import DevTool from "../lib/DevTool/DevTool";
|
|
4
|
+
import { Iconify } from "@canmingir/link/platform/components";
|
|
5
|
+
import React from "react";
|
|
6
|
+
import SidebarChat from "../lib/SidebarChat/SidebarChat";
|
|
7
|
+
|
|
8
|
+
import { ThemeProvider, createTheme } from "@mui/material/styles";
|
|
9
|
+
|
|
10
|
+
const lightTheme = createTheme({
|
|
11
|
+
palette: { mode: "light", primary: { main: "#1976d2" } },
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
const now = Date.now();
|
|
15
|
+
|
|
16
|
+
const makeMessages = (n) =>
|
|
17
|
+
Array.from({ length: n }, (_, i) => ({
|
|
18
|
+
id: `m-${i}`,
|
|
19
|
+
role: i % 2 === 0 ? "user" : "assistant",
|
|
20
|
+
content:
|
|
21
|
+
i % 2 === 0
|
|
22
|
+
? `Question number ${i / 2 + 1}?`
|
|
23
|
+
: `Answer number ${Math.ceil(i / 2)}. Lorem ipsum dolor sit amet.`,
|
|
24
|
+
}));
|
|
25
|
+
|
|
26
|
+
const storedSessions = [
|
|
27
|
+
{
|
|
28
|
+
sessionId: "sess-1",
|
|
29
|
+
messages: makeMessages(6),
|
|
30
|
+
lastUpdated: now - 1000 * 60 * 20,
|
|
31
|
+
agentName: "Planner",
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
sessionId: "sess-2",
|
|
35
|
+
messages: makeMessages(3),
|
|
36
|
+
lastUpdated: now - 1000 * 60 * 5,
|
|
37
|
+
agentIcon: "solar:rocket-bold-duotone",
|
|
38
|
+
agentName: "Builder",
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
sessionId: "sess-3",
|
|
42
|
+
messages: makeMessages(11),
|
|
43
|
+
lastUpdated: now - 1000 * 60,
|
|
44
|
+
agentName: "Reviewer",
|
|
45
|
+
},
|
|
46
|
+
];
|
|
47
|
+
|
|
48
|
+
const noop = () => {};
|
|
49
|
+
|
|
50
|
+
const Frame = ({ children, theme = lightTheme }) => (
|
|
51
|
+
<ThemeProvider theme={theme}>
|
|
52
|
+
<CssBaseline />
|
|
53
|
+
<Box
|
|
54
|
+
sx={{
|
|
55
|
+
position: "relative",
|
|
56
|
+
width: "100%",
|
|
57
|
+
minWidth: 640,
|
|
58
|
+
minHeight: 520,
|
|
59
|
+
border: "1px dashed",
|
|
60
|
+
borderColor: "divider",
|
|
61
|
+
borderRadius: 2,
|
|
62
|
+
bgcolor: "background.default",
|
|
63
|
+
overflow: "hidden",
|
|
64
|
+
}}
|
|
65
|
+
>
|
|
66
|
+
<Box sx={{ p: 3, color: "text.secondary", fontSize: 13 }}>
|
|
67
|
+
App content — the DevTool docks to the right edge.
|
|
68
|
+
</Box>
|
|
69
|
+
{children}
|
|
70
|
+
</Box>
|
|
71
|
+
</ThemeProvider>
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
export default {
|
|
75
|
+
title: "Lib/DevTool",
|
|
76
|
+
parameters: {
|
|
77
|
+
layout: "fullscreen",
|
|
78
|
+
docs: {
|
|
79
|
+
description: {
|
|
80
|
+
component: `
|
|
81
|
+
\`DevTool\` is the top-level right-side shell. It has **two modes in one component**:
|
|
82
|
+
|
|
83
|
+
- **Slot mode** (no \`children\`, or \`children\` is a node) — a plain glass box with
|
|
84
|
+
\`header\` / \`content\` / \`footer\` slots. Used internally by \`SidebarSessionList\`
|
|
85
|
+
to draw the rail.
|
|
86
|
+
- **Shell mode** (\`children\` is a **function**) — renders the collapsed session
|
|
87
|
+
rail + session popover and hosts the chat surface as the wide drawer.
|
|
88
|
+
|
|
89
|
+
In shell mode \`children\` is a **render prop**: DevTool owns the session state and
|
|
90
|
+
passes it to the function, which returns the chat element (typically
|
|
91
|
+
\`<SidebarChat />\`):
|
|
92
|
+
|
|
93
|
+
\`\`\`jsx
|
|
94
|
+
<DevTool open={open} sessionId={id} history={history} storedSessions={...}>
|
|
95
|
+
{({ open, handleToggle, selectedConversationId, sessionId, history, onNewSession }) => (
|
|
96
|
+
<SidebarChat
|
|
97
|
+
title="Assistant"
|
|
98
|
+
open={open}
|
|
99
|
+
handleToggle={handleToggle}
|
|
100
|
+
selectedConversationId={selectedConversationId}
|
|
101
|
+
sessionId={sessionId}
|
|
102
|
+
history={history}
|
|
103
|
+
onNewSession={onNewSession}
|
|
104
|
+
handleNewUserMessage={send}
|
|
105
|
+
/>
|
|
106
|
+
)}
|
|
107
|
+
</DevTool>
|
|
108
|
+
\`\`\`
|
|
109
|
+
|
|
110
|
+
Pass \`open\` to toggle between the collapsed rail and the open chat drawer.
|
|
111
|
+
`,
|
|
112
|
+
},
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
const renderChat =
|
|
118
|
+
(extra = {}) =>
|
|
119
|
+
(ctx) =>
|
|
120
|
+
(
|
|
121
|
+
<SidebarChat
|
|
122
|
+
title="Assistant"
|
|
123
|
+
handleNewUserMessage={noop}
|
|
124
|
+
open={ctx.open}
|
|
125
|
+
handleToggle={ctx.handleToggle}
|
|
126
|
+
selectedConversationId={ctx.selectedConversationId}
|
|
127
|
+
sessionId={ctx.sessionId}
|
|
128
|
+
history={ctx.history}
|
|
129
|
+
onNewSession={ctx.onNewSession}
|
|
130
|
+
{...extra}
|
|
131
|
+
/>
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
export const SlotMode = {
|
|
135
|
+
name: "Slot mode — header / content / footer",
|
|
136
|
+
render: () => (
|
|
137
|
+
<Frame>
|
|
138
|
+
<DevTool
|
|
139
|
+
open
|
|
140
|
+
width={62}
|
|
141
|
+
height={280}
|
|
142
|
+
header={<Box sx={{ fontSize: 11, fontWeight: 700, py: 0.5 }}>TOP</Box>}
|
|
143
|
+
content={
|
|
144
|
+
<Box sx={{ display: "flex", flexDirection: "column", gap: 1, py: 1 }}>
|
|
145
|
+
{["A", "B", "C", "D"].map((x) => (
|
|
146
|
+
<Box
|
|
147
|
+
key={x}
|
|
148
|
+
sx={{
|
|
149
|
+
width: 32,
|
|
150
|
+
height: 32,
|
|
151
|
+
borderRadius: "10px",
|
|
152
|
+
display: "flex",
|
|
153
|
+
alignItems: "center",
|
|
154
|
+
justifyContent: "center",
|
|
155
|
+
bgcolor: "action.hover",
|
|
156
|
+
fontSize: 12,
|
|
157
|
+
fontWeight: 700,
|
|
158
|
+
}}
|
|
159
|
+
>
|
|
160
|
+
{x}
|
|
161
|
+
</Box>
|
|
162
|
+
))}
|
|
163
|
+
</Box>
|
|
164
|
+
}
|
|
165
|
+
footer={
|
|
166
|
+
<Iconify icon="solar:trash-bin-2-bold" width={18} height={18} />
|
|
167
|
+
}
|
|
168
|
+
/>
|
|
169
|
+
</Frame>
|
|
170
|
+
),
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
export const SlotModeClosed = {
|
|
174
|
+
name: "Slot mode — open={false} renders nothing",
|
|
175
|
+
render: () => (
|
|
176
|
+
<Frame>
|
|
177
|
+
<DevTool open={false} content={<Box>you should not see this</Box>} />
|
|
178
|
+
<Box sx={{ position: "absolute", bottom: 12, left: 12, fontSize: 12 }}>
|
|
179
|
+
DevTool returned null — canvas is empty on the right.
|
|
180
|
+
</Box>
|
|
181
|
+
</Frame>
|
|
182
|
+
),
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
const shellProps = {
|
|
186
|
+
handleToggle: noop,
|
|
187
|
+
selectedConversationId: "sess-3",
|
|
188
|
+
sessionId: "sess-3",
|
|
189
|
+
history: makeMessages(11),
|
|
190
|
+
storedSessions,
|
|
191
|
+
refreshSessions: noop,
|
|
192
|
+
clearAllSessions: noop,
|
|
193
|
+
onSessionSelect: noop,
|
|
194
|
+
onNewSession: noop,
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
export const ShellCollapsed = {
|
|
198
|
+
name: "Shell — collapsed rail (open={false})",
|
|
199
|
+
render: () => (
|
|
200
|
+
<Frame>
|
|
201
|
+
<DevTool {...shellProps} open={false}>
|
|
202
|
+
{renderChat()}
|
|
203
|
+
</DevTool>
|
|
204
|
+
</Frame>
|
|
205
|
+
),
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
export const ShellCollapsedBeta = {
|
|
209
|
+
name: "Shell — collapsed rail, beta (no Swagger button)",
|
|
210
|
+
render: () => (
|
|
211
|
+
<Frame>
|
|
212
|
+
<DevTool {...shellProps} open={false} beta>
|
|
213
|
+
{renderChat()}
|
|
214
|
+
</DevTool>
|
|
215
|
+
</Frame>
|
|
216
|
+
),
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
export const ShellCollapsedWithTopAction = {
|
|
220
|
+
name: "Shell — collapsed rail + topAction button",
|
|
221
|
+
render: () => (
|
|
222
|
+
<Frame>
|
|
223
|
+
<DevTool
|
|
224
|
+
{...shellProps}
|
|
225
|
+
open={false}
|
|
226
|
+
topAction={{
|
|
227
|
+
icon: "solar:folder-with-files-bold-duotone",
|
|
228
|
+
label: "Context",
|
|
229
|
+
tooltip: "Open context panel",
|
|
230
|
+
onClick: noop,
|
|
231
|
+
}}
|
|
232
|
+
>
|
|
233
|
+
{renderChat()}
|
|
234
|
+
</DevTool>
|
|
235
|
+
</Frame>
|
|
236
|
+
),
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
export const ShellCollapsedNoSessions = {
|
|
240
|
+
name: "Shell — collapsed rail, no sessions",
|
|
241
|
+
render: () => (
|
|
242
|
+
<Frame>
|
|
243
|
+
<DevTool
|
|
244
|
+
{...shellProps}
|
|
245
|
+
open={false}
|
|
246
|
+
storedSessions={[]}
|
|
247
|
+
selectedConversationId={undefined}
|
|
248
|
+
sessionId={undefined}
|
|
249
|
+
history={[]}
|
|
250
|
+
>
|
|
251
|
+
{renderChat()}
|
|
252
|
+
</DevTool>
|
|
253
|
+
</Frame>
|
|
254
|
+
),
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
export const ShellOpen = {
|
|
258
|
+
name: "Shell — open chat drawer",
|
|
259
|
+
render: () => (
|
|
260
|
+
<Frame>
|
|
261
|
+
<DevTool {...shellProps} open>
|
|
262
|
+
{renderChat()}
|
|
263
|
+
</DevTool>
|
|
264
|
+
</Frame>
|
|
265
|
+
),
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
export const ShellOpenReadOnly = {
|
|
269
|
+
name: "Shell — open chat drawer, read-only",
|
|
270
|
+
render: () => (
|
|
271
|
+
<Frame>
|
|
272
|
+
<DevTool {...shellProps} open>
|
|
273
|
+
{renderChat({ readOnly: true, title: "Assistant (history)" })}
|
|
274
|
+
</DevTool>
|
|
275
|
+
</Frame>
|
|
276
|
+
),
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
export const ShellOpenEmpty = {
|
|
280
|
+
name: "Shell — open chat drawer, empty conversation",
|
|
281
|
+
render: () => (
|
|
282
|
+
<Frame>
|
|
283
|
+
<DevTool
|
|
284
|
+
{...shellProps}
|
|
285
|
+
open
|
|
286
|
+
history={[]}
|
|
287
|
+
storedSessions={[]}
|
|
288
|
+
selectedConversationId={undefined}
|
|
289
|
+
sessionId={undefined}
|
|
290
|
+
>
|
|
291
|
+
{renderChat()}
|
|
292
|
+
</DevTool>
|
|
293
|
+
</Frame>
|
|
294
|
+
),
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
export const ShellInteractive = {
|
|
298
|
+
name: "Shell — interactive (toggle + send)",
|
|
299
|
+
render: () => {
|
|
300
|
+
const [open, setOpen] = React.useState(false);
|
|
301
|
+
const [history, setHistory] = React.useState(makeMessages(4));
|
|
302
|
+
|
|
303
|
+
const toggle = () => setOpen((o) => !o);
|
|
304
|
+
const send = (msg) =>
|
|
305
|
+
setHistory((h) => [
|
|
306
|
+
...h,
|
|
307
|
+
{ id: `u-${h.length}`, role: "user", content: msg },
|
|
308
|
+
]);
|
|
309
|
+
const reset = () => setHistory([]);
|
|
310
|
+
|
|
311
|
+
return (
|
|
312
|
+
<Frame>
|
|
313
|
+
<DevTool
|
|
314
|
+
{...shellProps}
|
|
315
|
+
open={open}
|
|
316
|
+
handleToggle={toggle}
|
|
317
|
+
history={history}
|
|
318
|
+
onNewSession={reset}
|
|
319
|
+
>
|
|
320
|
+
{(ctx) => (
|
|
321
|
+
<SidebarChat
|
|
322
|
+
title="Assistant"
|
|
323
|
+
open={ctx.open}
|
|
324
|
+
handleToggle={ctx.handleToggle}
|
|
325
|
+
selectedConversationId={ctx.selectedConversationId}
|
|
326
|
+
sessionId={ctx.sessionId}
|
|
327
|
+
history={ctx.history}
|
|
328
|
+
onNewSession={ctx.onNewSession}
|
|
329
|
+
handleNewUserMessage={send}
|
|
330
|
+
/>
|
|
331
|
+
)}
|
|
332
|
+
</DevTool>
|
|
333
|
+
</Frame>
|
|
334
|
+
);
|
|
335
|
+
},
|
|
336
|
+
};
|