ai-design-system 0.1.63 → 0.1.64
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/components/composites/SessionHeader/SessionHeader.tsx +27 -2
- package/components/features/RefinementPanel/RefinementPanel.tsx +7 -0
- package/components/features/RefinementPanel/useRefinementPanel.d.ts +4 -0
- package/dist/index.cjs +23 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +8 -0
- package/dist/index.js +23 -5
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -16,12 +16,16 @@ export interface ChatSessionInfo {
|
|
|
16
16
|
created_at: string;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
+
import type { FileDownloadResult } from '@/components/composites/FileTreeExplorer';
|
|
20
|
+
|
|
21
|
+
|
|
19
22
|
export interface SessionHeaderProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
20
23
|
sessions?: ChatSessionInfo[];
|
|
21
24
|
activeSessionId?: string | null;
|
|
22
25
|
onNewSession?: () => void;
|
|
23
26
|
onCloseSession?: (id: string) => void;
|
|
24
27
|
onSelectSession?: (id: string) => void;
|
|
28
|
+
onDownloadSession?: () => Promise<FileDownloadResult | undefined>;
|
|
25
29
|
}
|
|
26
30
|
|
|
27
31
|
/**
|
|
@@ -31,8 +35,23 @@ export interface SessionHeaderProps extends React.HTMLAttributes<HTMLDivElement>
|
|
|
31
35
|
* and a dropdown history of past sessions.
|
|
32
36
|
*/
|
|
33
37
|
export const SessionHeader = React.forwardRef<HTMLDivElement, SessionHeaderProps>(
|
|
34
|
-
({ sessions, activeSessionId, onNewSession, onCloseSession, onSelectSession, className, ...props }, ref) => {
|
|
38
|
+
({ sessions, activeSessionId, onNewSession, onCloseSession, onSelectSession, onDownloadSession, className, ...props }, ref) => {
|
|
35
39
|
const activeSession = sessions?.find(s => s.id === activeSessionId);
|
|
40
|
+
const downloadRef = React.useRef<HTMLAnchorElement>(null);
|
|
41
|
+
|
|
42
|
+
const handleDownloadClick = React.useCallback(async () => {
|
|
43
|
+
if (!onDownloadSession) return;
|
|
44
|
+
const result = await onDownloadSession();
|
|
45
|
+
if (!result) return;
|
|
46
|
+
const url = URL.createObjectURL(result.blob);
|
|
47
|
+
const anchor = downloadRef.current;
|
|
48
|
+
if (anchor) {
|
|
49
|
+
anchor.href = url;
|
|
50
|
+
anchor.download = result.filename;
|
|
51
|
+
anchor.click();
|
|
52
|
+
}
|
|
53
|
+
URL.revokeObjectURL(url);
|
|
54
|
+
}, [onDownloadSession]);
|
|
36
55
|
|
|
37
56
|
return (
|
|
38
57
|
<div
|
|
@@ -48,7 +67,12 @@ export const SessionHeader = React.forwardRef<HTMLDivElement, SessionHeaderProps
|
|
|
48
67
|
</span>
|
|
49
68
|
</div>
|
|
50
69
|
<div className="flex items-center space-x-1 flex-none">
|
|
51
|
-
|
|
70
|
+
{onDownloadSession && (
|
|
71
|
+
<Button variant="ghost" size="icon" onClick={handleDownloadClick} className="h-8 w-8" title="Download Chat History">
|
|
72
|
+
<Icon name="download" className="h-4 w-4" />
|
|
73
|
+
</Button>
|
|
74
|
+
)}
|
|
75
|
+
<Button variant="ghost" size="icon" onClick={onNewSession} className="h-8 w-8" title="New Session">
|
|
52
76
|
<Icon name="plus" className="h-4 w-4" />
|
|
53
77
|
</Button>
|
|
54
78
|
|
|
@@ -77,6 +101,7 @@ export const SessionHeader = React.forwardRef<HTMLDivElement, SessionHeaderProps
|
|
|
77
101
|
)}
|
|
78
102
|
</DropdownMenuContent>
|
|
79
103
|
</DropdownMenu>
|
|
104
|
+
<a ref={downloadRef} style={{ display: 'none' }} />
|
|
80
105
|
</div>
|
|
81
106
|
</div>
|
|
82
107
|
);
|
|
@@ -13,6 +13,7 @@ import type { ActionRequest, ReviewConfig, ToolUIState, ToolApproval } from "@/c
|
|
|
13
13
|
import type { FormEvent } from "react";
|
|
14
14
|
import { SessionHeader } from "@/components/composites/SessionHeader";
|
|
15
15
|
import type { ChatSessionInfo } from "@/components/composites/SessionHeader";
|
|
16
|
+
import type { FileDownloadResult } from "@/components/composites/FileTreeExplorer";
|
|
16
17
|
|
|
17
18
|
/**
|
|
18
19
|
* RefinementPanel Feature
|
|
@@ -127,6 +128,10 @@ export interface RefinementPanelProps {
|
|
|
127
128
|
* Handler to switch sessions
|
|
128
129
|
*/
|
|
129
130
|
onSelectSession?: (id: string) => void;
|
|
131
|
+
/**
|
|
132
|
+
* Handler to download the session chat history
|
|
133
|
+
*/
|
|
134
|
+
onDownloadSession?: () => Promise<FileDownloadResult | undefined>;
|
|
130
135
|
}
|
|
131
136
|
|
|
132
137
|
/**
|
|
@@ -154,6 +159,7 @@ export const RefinementPanel = React.memo<RefinementPanelProps>(
|
|
|
154
159
|
onNewSession,
|
|
155
160
|
onCloseSession,
|
|
156
161
|
onSelectSession,
|
|
162
|
+
onDownloadSession,
|
|
157
163
|
}) => {
|
|
158
164
|
// File change queue state
|
|
159
165
|
const [fileChangeState, setFileChangeState] = React.useState<
|
|
@@ -298,6 +304,7 @@ export const RefinementPanel = React.memo<RefinementPanelProps>(
|
|
|
298
304
|
onNewSession={onNewSession}
|
|
299
305
|
onCloseSession={onCloseSession}
|
|
300
306
|
onSelectSession={onSelectSession}
|
|
307
|
+
onDownloadSession={onDownloadSession}
|
|
301
308
|
/>
|
|
302
309
|
|
|
303
310
|
<AIConversation
|
|
@@ -12,6 +12,7 @@ import type { RefinementMessage } from "./RefinementPanel";
|
|
|
12
12
|
import type { FileChangeData } from "@/components/composites/FileQueue";
|
|
13
13
|
import type { ActionRequest, ReviewConfig } from "@/components/composites/ApprovalCard";
|
|
14
14
|
import type { ToolCall } from "@/components/composites/ToolCallDisplay";
|
|
15
|
+
import type { FileDownloadResult } from "@/components/composites/FileTreeExplorer";
|
|
15
16
|
|
|
16
17
|
/**
|
|
17
18
|
* Return type for the refinement panel hook
|
|
@@ -55,6 +56,9 @@ export interface UseRefinementPanelReturn {
|
|
|
55
56
|
|
|
56
57
|
/** Action handler for tool interactions */
|
|
57
58
|
handleToolAction?: (toolCall: ToolCall, action: string) => void;
|
|
59
|
+
|
|
60
|
+
/** Handler to download the session chat history */
|
|
61
|
+
handleDownloadSession?: () => Promise<FileDownloadResult | undefined>;
|
|
58
62
|
}
|
|
59
63
|
|
|
60
64
|
/**
|
package/dist/index.cjs
CHANGED
|
@@ -6005,8 +6005,22 @@ var ApprovalCard = React3__namespace.memo(
|
|
|
6005
6005
|
ApprovalCard.displayName = "ApprovalCard";
|
|
6006
6006
|
var SessionHeader = React3__namespace.forwardRef(
|
|
6007
6007
|
(_a, ref) => {
|
|
6008
|
-
var _b = _a, { sessions, activeSessionId, onNewSession, onCloseSession, onSelectSession, className } = _b, props = __objRest(_b, ["sessions", "activeSessionId", "onNewSession", "onCloseSession", "onSelectSession", "className"]);
|
|
6008
|
+
var _b = _a, { sessions, activeSessionId, onNewSession, onCloseSession, onSelectSession, onDownloadSession, className } = _b, props = __objRest(_b, ["sessions", "activeSessionId", "onNewSession", "onCloseSession", "onSelectSession", "onDownloadSession", "className"]);
|
|
6009
6009
|
const activeSession = sessions == null ? void 0 : sessions.find((s) => s.id === activeSessionId);
|
|
6010
|
+
const downloadRef = React3__namespace.useRef(null);
|
|
6011
|
+
const handleDownloadClick = React3__namespace.useCallback(async () => {
|
|
6012
|
+
if (!onDownloadSession) return;
|
|
6013
|
+
const result = await onDownloadSession();
|
|
6014
|
+
if (!result) return;
|
|
6015
|
+
const url = URL.createObjectURL(result.blob);
|
|
6016
|
+
const anchor = downloadRef.current;
|
|
6017
|
+
if (anchor) {
|
|
6018
|
+
anchor.href = url;
|
|
6019
|
+
anchor.download = result.filename;
|
|
6020
|
+
anchor.click();
|
|
6021
|
+
}
|
|
6022
|
+
URL.revokeObjectURL(url);
|
|
6023
|
+
}, [onDownloadSession]);
|
|
6010
6024
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
6011
6025
|
"div",
|
|
6012
6026
|
__spreadProps(__spreadValues({
|
|
@@ -6016,7 +6030,8 @@ var SessionHeader = React3__namespace.forwardRef(
|
|
|
6016
6030
|
children: [
|
|
6017
6031
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center space-x-2 overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium truncate", children: activeSessionId ? (activeSession == null ? void 0 : activeSession.title) || "Untitled Session" : "New Session" }) }),
|
|
6018
6032
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center space-x-1 flex-none", children: [
|
|
6019
|
-
/* @__PURE__ */ jsxRuntime.jsx(Button2, { variant: "ghost", size: "icon", onClick:
|
|
6033
|
+
onDownloadSession && /* @__PURE__ */ jsxRuntime.jsx(Button2, { variant: "ghost", size: "icon", onClick: handleDownloadClick, className: "h-8 w-8", title: "Download Chat History", children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "download", className: "h-4 w-4" }) }),
|
|
6034
|
+
/* @__PURE__ */ jsxRuntime.jsx(Button2, { variant: "ghost", size: "icon", onClick: onNewSession, className: "h-8 w-8", title: "New Session", children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "plus", className: "h-4 w-4" }) }),
|
|
6020
6035
|
/* @__PURE__ */ jsxRuntime.jsxs(DropdownMenu2, { children: [
|
|
6021
6036
|
/* @__PURE__ */ jsxRuntime.jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(Button2, { variant: "ghost", size: "icon", className: "h-8 w-8", children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "clock", className: "h-4 w-4" }) }) }),
|
|
6022
6037
|
/* @__PURE__ */ jsxRuntime.jsxs(DropdownMenuContent, { align: "end", className: "w-64 max-h-80 overflow-y-auto", children: [
|
|
@@ -6035,7 +6050,8 @@ var SessionHeader = React3__namespace.forwardRef(
|
|
|
6035
6050
|
session.id
|
|
6036
6051
|
)) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4 text-sm text-center text-muted-foreground", children: "No previous sessions" })
|
|
6037
6052
|
] })
|
|
6038
|
-
] })
|
|
6053
|
+
] }),
|
|
6054
|
+
/* @__PURE__ */ jsxRuntime.jsx("a", { ref: downloadRef, style: { display: "none" } })
|
|
6039
6055
|
] })
|
|
6040
6056
|
]
|
|
6041
6057
|
})
|
|
@@ -6064,7 +6080,8 @@ var RefinementPanel = React3__namespace.memo(
|
|
|
6064
6080
|
activeSessionId,
|
|
6065
6081
|
onNewSession,
|
|
6066
6082
|
onCloseSession,
|
|
6067
|
-
onSelectSession
|
|
6083
|
+
onSelectSession,
|
|
6084
|
+
onDownloadSession
|
|
6068
6085
|
}) => {
|
|
6069
6086
|
const [fileChangeState, setFileChangeState] = React3__namespace.useState("approval-requested");
|
|
6070
6087
|
const [approval, setApproval] = React3__namespace.useState({});
|
|
@@ -6177,7 +6194,8 @@ var RefinementPanel = React3__namespace.memo(
|
|
|
6177
6194
|
activeSessionId,
|
|
6178
6195
|
onNewSession,
|
|
6179
6196
|
onCloseSession,
|
|
6180
|
-
onSelectSession
|
|
6197
|
+
onSelectSession,
|
|
6198
|
+
onDownloadSession
|
|
6181
6199
|
}
|
|
6182
6200
|
),
|
|
6183
6201
|
/* @__PURE__ */ jsxRuntime.jsx(
|