@parallelworks/ui 0.34.0 → 0.36.0
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/README.md +201 -0
- package/dist/ai/components/ChatEmptyState.js +71 -86
- package/dist/ai/components/ChatInput.d.ts +11 -3
- package/dist/ai/components/ChatInput.js +19 -11
- package/dist/ai/components/ChatSidebar.js +12 -130
- package/dist/ai/components/ChatStage.d.ts +11 -0
- package/dist/ai/components/ChatStage.js +26 -0
- package/dist/ai/components/ComposerChrome.d.ts +3 -0
- package/dist/ai/components/ComposerChrome.js +21 -2
- package/dist/ai/components/agent/AgentMessageParts.js +8 -2
- package/dist/ai/components/conversationActions.d.ts +23 -0
- package/dist/ai/components/conversationActions.js +108 -0
- package/dist/ai/index.d.ts +4 -3
- package/dist/ai/index.js +6 -5
- package/dist/ai/strings.d.ts +7 -0
- package/dist/ai/strings.js +8 -1
- package/dist/ai/types.d.ts +2 -0
- package/dist/ai/ui/ConversationSidebar.d.ts +3 -2
- package/dist/ai/ui/ConversationSidebar.js +2 -1
- package/dist/ai/ui/sidebar.d.ts +6 -0
- package/dist/ai/ui/sidebar.js +10 -1
- package/dist/components/Dropdown.js +3 -1
- package/dist/components/FilterPill.js +1 -0
- package/dist/components/Provider.d.ts +14 -0
- package/dist/components/Provider.js +14 -3
- package/dist/components/SegmentedControl.d.ts +24 -0
- package/dist/components/SegmentedControl.js +69 -0
- package/dist/editing.d.ts +32 -0
- package/dist/editor/FormCodePanel.js +1 -1
- package/dist/engine.d.ts +3 -0
- package/dist/form/FieldWrapper.js +1 -1
- package/dist/form/Fields/CheckboxGroupField.d.ts +3 -3
- package/dist/form/Fields/CheckboxGroupField.js +10 -4
- package/dist/form/Fields/RadioField.d.ts +5 -3
- package/dist/form/Fields/RadioField.js +25 -17
- package/dist/form/Fields/fieldOption.d.ts +12 -0
- package/dist/form/Fields/fieldOption.js +17 -0
- package/dist/form/Form.d.ts +4 -2
- package/dist/form/Form.js +170 -68
- package/dist/form/FormLayout.d.ts +7 -0
- package/dist/form/FormLayout.js +144 -0
- package/dist/form/SpecialTypes/FormikCustomDropdown.js +1 -1
- package/dist/form/SpecialTypes/FormikCustomInput.js +7 -0
- package/dist/form/Wizard/WizardContainer.d.ts +1 -1
- package/dist/form/Wizard/WizardContainer.js +244 -49
- package/dist/form/Wizard/WizardNavigation.js +4 -4
- package/dist/form/Wizard/WizardStepContent.d.ts +1 -1
- package/dist/form/Wizard/WizardStepContent.js +19 -10
- package/dist/form/Wizard/WizardStepIndicator.js +35 -7
- package/dist/form/Wizard/types.d.ts +19 -6
- package/dist/form/Wizard/useWizardState.d.ts +1 -0
- package/dist/form/Wizard/useWizardState.js +5 -1
- package/dist/form/Wizard/utils.d.ts +7 -0
- package/dist/form/Wizard/utils.js +18 -1
- package/dist/form/index.d.ts +2 -0
- package/dist/form/index.js +4 -2
- package/dist/form/layout.d.ts +50 -0
- package/dist/form/layout.js +125 -0
- package/dist/form/layoutCSS.d.ts +10 -0
- package/dist/form/layoutCSS.js +234 -0
- package/dist/form/lib.d.ts +2 -0
- package/dist/form/lib.js +17 -2
- package/dist/form/types/fieldTypes.d.ts +8 -23
- package/dist/graph/DependencyGraph.d.ts +20 -1
- package/dist/graph/DependencyGraph.js +437 -142
- package/dist/graph/MatrixGroup.d.ts +3 -1
- package/dist/graph/MatrixGroup.js +31 -28
- package/dist/graph/TreeView.js +6 -6
- package/dist/graph/gridSpacing.d.ts +7 -0
- package/dist/graph/gridSpacing.js +10 -0
- package/dist/graph/util.d.ts +2 -0
- package/dist/graph/util.js +2 -2
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -1
- package/dist/list/ListViewControls.d.ts +15 -0
- package/dist/list/ListViewControls.js +9 -3
- package/dist/list/index.d.ts +1 -1
- package/dist/list/index.js +2 -2
- package/dist/styles/base.css +3 -1
- package/dist/styles/theme.css +5 -0
- package/dist/styles.css +1 -1
- package/dist/theme/index.d.ts +2 -0
- package/dist/theme/index.js +3 -2
- package/package.json +4 -2
- package/dist/ai/components/ComposerFrame.d.ts +0 -16
- package/dist/ai/components/ComposerFrame.js +0 -33
|
@@ -1,76 +1,21 @@
|
|
|
1
|
-
import { BiSolidTrashAlt } from "../../icons/bi/BiSolidTrashAlt.js";
|
|
2
|
-
import { FaCloudDownloadAlt } from "../../icons/fa/FaCloudDownloadAlt.js";
|
|
3
|
-
import { FaEdit } from "../../icons/fa/FaEdit.js";
|
|
4
1
|
import { FaRegFileImage } from "../../icons/fa/FaRegFileImage.js";
|
|
5
2
|
import { FaSearch } from "../../icons/fa/FaSearch.js";
|
|
6
3
|
import { FaUsers } from "../../icons/fa/FaUsers.js";
|
|
7
|
-
import { IoSettingsOutline } from "../../icons/io5/IoSettingsOutline.js";
|
|
8
|
-
import { PiShareBold } from "../../icons/pi/PiShareBold.js";
|
|
9
4
|
import { TbEdit } from "../../icons/tb/TbEdit.js";
|
|
10
|
-
import { useRowMenu } from "../../list/RowContextMenu.js";
|
|
11
5
|
import { useChatConfig } from "../core/config.js";
|
|
12
6
|
import { useChat } from "../core/ChatProvider.js";
|
|
7
|
+
import { ManageProvidersLink } from "./ComposerChrome.js";
|
|
13
8
|
import { FOCUS_SIDEBAR_SEARCH_EVENT } from "../core/events.js";
|
|
14
|
-
import {
|
|
15
|
-
import { conversationToMarkdown, downloadText, exportFilename } from "../core/exportConversation.js";
|
|
9
|
+
import { SidebarPlaceholder, SidebarRow } from "../ui/sidebar.js";
|
|
16
10
|
import { ConversationSidebar } from "../ui/ConversationSidebar.js";
|
|
17
|
-
import
|
|
11
|
+
import { groupConversationsByDate, useConversationActions } from "./conversationActions.js";
|
|
18
12
|
import cx from "classnames";
|
|
19
13
|
import { useEffect, useMemo, useRef, useState } from "react";
|
|
20
14
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
21
|
-
import { DateTime } from "luxon";
|
|
22
15
|
//#region src/ai/components/ChatSidebar.tsx
|
|
23
|
-
|
|
24
|
-
function groupByDate(conversations) {
|
|
25
|
-
const now = DateTime.now();
|
|
26
|
-
const groups = {
|
|
27
|
-
groupToday: [],
|
|
28
|
-
groupYesterday: [],
|
|
29
|
-
groupThisWeek: [],
|
|
30
|
-
groupThisMonth: [],
|
|
31
|
-
groupOlder: []
|
|
32
|
-
};
|
|
33
|
-
for (const conv of conversations) {
|
|
34
|
-
const dt = DateTime.fromISO(conv.createdAt);
|
|
35
|
-
const diff = now.diff(dt, "days").days;
|
|
36
|
-
if (diff < 1) groups.groupToday.push(conv);
|
|
37
|
-
else if (diff < 2) groups.groupYesterday.push(conv);
|
|
38
|
-
else if (diff < 7) groups.groupThisWeek.push(conv);
|
|
39
|
-
else if (diff < 30) groups.groupThisMonth.push(conv);
|
|
40
|
-
else groups.groupOlder.push(conv);
|
|
41
|
-
}
|
|
42
|
-
return Object.entries(groups).filter(([, items]) => items.length > 0);
|
|
43
|
-
}
|
|
44
|
-
function ConversationRow({ conv, isCurrent, sharingAvailable, openMenu, onRename, onShare, onDelete, onExport, onOpen }) {
|
|
16
|
+
function ConversationRow({ conv, isCurrent, menuItems, openMenu, onOpen }) {
|
|
45
17
|
const { LinkComponent, strings } = useChatConfig();
|
|
46
18
|
const t = strings.sidebar;
|
|
47
|
-
const menuItems = [
|
|
48
|
-
{
|
|
49
|
-
kind: "action",
|
|
50
|
-
label: t.rename,
|
|
51
|
-
icon: /* @__PURE__ */ jsx(FaEdit, {}),
|
|
52
|
-
onSelect: () => onRename(conv)
|
|
53
|
-
},
|
|
54
|
-
...sharingAvailable ? [{
|
|
55
|
-
kind: "action",
|
|
56
|
-
label: t.share,
|
|
57
|
-
icon: /* @__PURE__ */ jsx(PiShareBold, {}),
|
|
58
|
-
onSelect: () => onShare(conv.id)
|
|
59
|
-
}] : [],
|
|
60
|
-
{
|
|
61
|
-
kind: "action",
|
|
62
|
-
label: strings.chrome.download,
|
|
63
|
-
icon: /* @__PURE__ */ jsx(FaCloudDownloadAlt, {}),
|
|
64
|
-
onSelect: () => onExport(conv.id)
|
|
65
|
-
},
|
|
66
|
-
{
|
|
67
|
-
kind: "action",
|
|
68
|
-
label: t.delete,
|
|
69
|
-
icon: /* @__PURE__ */ jsx(BiSolidTrashAlt, {}),
|
|
70
|
-
destructive: true,
|
|
71
|
-
onSelect: () => onDelete(conv)
|
|
72
|
-
}
|
|
73
|
-
];
|
|
74
19
|
return /* @__PURE__ */ jsx(SidebarRow, {
|
|
75
20
|
selected: isCurrent,
|
|
76
21
|
menuItems,
|
|
@@ -93,28 +38,11 @@ function ConversationRow({ conv, isCurrent, sharingAvailable, openMenu, onRename
|
|
|
93
38
|
});
|
|
94
39
|
}
|
|
95
40
|
function ChatSidebar({ actions = true, top }) {
|
|
96
|
-
const {
|
|
41
|
+
const { LinkComponent, strings } = useChatConfig();
|
|
97
42
|
const tSidebar = strings.sidebar;
|
|
98
|
-
const { adapter, navigation,
|
|
99
|
-
const sharingAvailable = !!adapter.sharing;
|
|
43
|
+
const { adapter, navigation, activeConversationId, conversations, sidebar, sidebarPresentation, drawerOpen, setSidebar, setDrawerOpen, toggleSidebar, isLoading, loadConversations, clearCurrentConversation } = useChat();
|
|
100
44
|
const attachmentsAvailable = !!adapter.attachments;
|
|
101
|
-
const
|
|
102
|
-
const [conversationToShare, setConversationToShare] = useState(null);
|
|
103
|
-
const { openMenu, contextMenu } = useRowMenu();
|
|
104
|
-
const { requestDelete, requestRename, dialogs } = useRowDialogs({
|
|
105
|
-
strings: {
|
|
106
|
-
deleteTitle: tSidebar.deleteTitle,
|
|
107
|
-
deleteBody: () => tSidebar.deleteBody,
|
|
108
|
-
deleteAction: tSidebar.deleteAction,
|
|
109
|
-
renameTitle: tSidebar.renameTitle,
|
|
110
|
-
renameLabel: tSidebar.renameLabel,
|
|
111
|
-
renamePlaceholder: tSidebar.renamePlaceholder,
|
|
112
|
-
renameAction: tSidebar.renameAction
|
|
113
|
-
},
|
|
114
|
-
nameOf: (conv) => conv.title || tSidebar.untitled,
|
|
115
|
-
onDelete: (conv) => deleteConversation(conv.id),
|
|
116
|
-
onRename: (conv, title) => updateConversationTitle(conv.id, title)
|
|
117
|
-
});
|
|
45
|
+
const { menuItems, openMenu, overlays } = useConversationActions();
|
|
118
46
|
const drawer = sidebarPresentation === "drawer";
|
|
119
47
|
const sidebarCollapsed = !drawer && sidebar !== "expanded";
|
|
120
48
|
const closeDrawer = () => setDrawerOpen(false);
|
|
@@ -146,23 +74,11 @@ function ChatSidebar({ actions = true, top }) {
|
|
|
146
74
|
search,
|
|
147
75
|
tSidebar.untitled
|
|
148
76
|
]);
|
|
149
|
-
const groups = useMemo(() =>
|
|
77
|
+
const groups = useMemo(() => groupConversationsByDate(filteredConversations).map(({ key, items }) => ({
|
|
150
78
|
key,
|
|
151
79
|
label: tSidebar[key],
|
|
152
80
|
items
|
|
153
81
|
})), [filteredConversations, tSidebar]);
|
|
154
|
-
const handleExport = async (id) => {
|
|
155
|
-
try {
|
|
156
|
-
const conversation = await adapter.conversations.get(id);
|
|
157
|
-
downloadText(exportFilename(conversation.title), conversationToMarkdown(conversation));
|
|
158
|
-
} catch {
|
|
159
|
-
notify.error(strings.chrome.exportError);
|
|
160
|
-
}
|
|
161
|
-
};
|
|
162
|
-
const handleShareClick = (id) => {
|
|
163
|
-
setConversationToShare(id);
|
|
164
|
-
setShareDialogOpen(true);
|
|
165
|
-
};
|
|
166
82
|
const handleNewChat = () => {
|
|
167
83
|
closeDrawer();
|
|
168
84
|
clearCurrentConversation();
|
|
@@ -182,7 +98,6 @@ function ChatSidebar({ actions = true, top }) {
|
|
|
182
98
|
close: tSidebar.closeSidebar
|
|
183
99
|
},
|
|
184
100
|
resize: {
|
|
185
|
-
storageKey: SIDEBAR_WIDTH_STORAGE_KEY,
|
|
186
101
|
label: tSidebar.resizeLabel,
|
|
187
102
|
hint: tSidebar.resizeHint
|
|
188
103
|
},
|
|
@@ -191,22 +106,12 @@ function ChatSidebar({ actions = true, top }) {
|
|
|
191
106
|
renderRow: (conv) => /* @__PURE__ */ jsx(ConversationRow, {
|
|
192
107
|
conv,
|
|
193
108
|
isCurrent: activeConversationId === conv.id,
|
|
194
|
-
|
|
109
|
+
menuItems: menuItems(conv),
|
|
195
110
|
openMenu,
|
|
196
|
-
onRename: requestRename,
|
|
197
|
-
onShare: handleShareClick,
|
|
198
|
-
onDelete: requestDelete,
|
|
199
|
-
onExport: handleExport,
|
|
200
111
|
onOpen: closeDrawer
|
|
201
112
|
}),
|
|
202
113
|
loading: isLoading,
|
|
203
|
-
placeholder: conversations.length === 0 ?
|
|
204
|
-
className: "theme-muted-text text-sm px-2 whitespace-nowrap",
|
|
205
|
-
children: tSidebar.noConversations
|
|
206
|
-
}) : /* @__PURE__ */ jsx("p", {
|
|
207
|
-
className: "theme-muted-text text-sm px-2",
|
|
208
|
-
children: strings.chrome.noMatches
|
|
209
|
-
}),
|
|
114
|
+
placeholder: /* @__PURE__ */ jsx(SidebarPlaceholder, { children: conversations.length === 0 ? tSidebar.noConversations : strings.chrome.noMatches }),
|
|
210
115
|
cycle: {
|
|
211
116
|
current: filteredConversations.find((conv) => conv.id === activeConversationId),
|
|
212
117
|
onSelect: (conv) => navigation.toConversation(conv.id)
|
|
@@ -253,32 +158,9 @@ function ChatSidebar({ actions = true, top }) {
|
|
|
253
158
|
})]
|
|
254
159
|
})
|
|
255
160
|
})] })] }),
|
|
256
|
-
footer:
|
|
257
|
-
target: {
|
|
258
|
-
kind: "external",
|
|
259
|
-
href: extraLinks.manageProviders
|
|
260
|
-
},
|
|
261
|
-
className: "flex min-w-0 items-center gap-2 rounded-md px-2 py-1.5 text-xs theme-muted-text transition-colors hover:chat-tint hover:theme-text",
|
|
262
|
-
title: tSidebar.manageProviders,
|
|
263
|
-
children: [/* @__PURE__ */ jsx(IoSettingsOutline, { className: "h-3.5 w-3.5 shrink-0" }), /* @__PURE__ */ jsx("span", {
|
|
264
|
-
className: "truncate",
|
|
265
|
-
children: tSidebar.manageProviders
|
|
266
|
-
})]
|
|
267
|
-
})
|
|
161
|
+
footer: /* @__PURE__ */ jsx(ManageProvidersLink, {})
|
|
268
162
|
});
|
|
269
|
-
return /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
270
|
-
(drawer || sidebar !== "hidden") && list,
|
|
271
|
-
contextMenu,
|
|
272
|
-
dialogs,
|
|
273
|
-
conversationToShare && /* @__PURE__ */ jsx(ShareDialog, {
|
|
274
|
-
conversationId: conversationToShare,
|
|
275
|
-
isOpen: shareDialogOpen,
|
|
276
|
-
onClose: () => {
|
|
277
|
-
setShareDialogOpen(false);
|
|
278
|
-
setConversationToShare(null);
|
|
279
|
-
}
|
|
280
|
-
})
|
|
281
|
-
] });
|
|
163
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [(drawer || sidebar !== "hidden") && list, overlays] });
|
|
282
164
|
}
|
|
283
165
|
//#endregion
|
|
284
166
|
export { ChatSidebar as default };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
/** Where a new conversation starts: the heading and the composer together, a
|
|
3
|
+
* little above centre, with what the surface offers next under the box. The
|
|
4
|
+
* composer keeps its place however much is under it, so surfaces that share
|
|
5
|
+
* the stage put it in the same spot; a long list scrolls instead. */
|
|
6
|
+
export default function ChatStage({ heading, subheading, children, }: {
|
|
7
|
+
heading?: ReactNode;
|
|
8
|
+
subheading?: ReactNode;
|
|
9
|
+
/** The composer, then whatever goes under it. */
|
|
10
|
+
children: ReactNode;
|
|
11
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
//#region src/ai/components/ChatStage.tsx
|
|
3
|
+
/** Where a new conversation starts: the heading and the composer together, a
|
|
4
|
+
* little above centre, with what the surface offers next under the box. The
|
|
5
|
+
* composer keeps its place however much is under it, so surfaces that share
|
|
6
|
+
* the stage put it in the same spot; a long list scrolls instead. */
|
|
7
|
+
function ChatStage({ heading, subheading, children }) {
|
|
8
|
+
return /* @__PURE__ */ jsx("div", {
|
|
9
|
+
className: "flex min-h-0 flex-1 flex-col overflow-y-auto [container-type:size] [scrollbar-gutter:stable_both-edges]",
|
|
10
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
11
|
+
className: "w-full pt-[max(2rem,24cqh)] pb-[12vh]",
|
|
12
|
+
children: [heading && /* @__PURE__ */ jsxs("div", {
|
|
13
|
+
className: "mx-auto mb-6 max-w-[var(--chat-column,50rem)] px-8 text-center",
|
|
14
|
+
children: [/* @__PURE__ */ jsx("h1", {
|
|
15
|
+
className: "text-[1.75rem] leading-tight font-medium tracking-[-0.02em] text-balance text-(--theme-panel)",
|
|
16
|
+
children: heading
|
|
17
|
+
}), subheading && /* @__PURE__ */ jsx("p", {
|
|
18
|
+
className: "mt-2 text-sm theme-muted-text",
|
|
19
|
+
children: subheading
|
|
20
|
+
})]
|
|
21
|
+
}), children]
|
|
22
|
+
})
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
//#endregion
|
|
26
|
+
export { ChatStage as default };
|
|
@@ -22,4 +22,7 @@ export declare function ComposerUsage({ children }: {
|
|
|
22
22
|
export declare function ComposerControls({ targetSession }: {
|
|
23
23
|
targetSession?: string | null | undefined;
|
|
24
24
|
}): import("react").JSX.Element;
|
|
25
|
+
/** Where the reader manages the providers behind the model picker, at the
|
|
26
|
+
* foot of a conversation list. */
|
|
27
|
+
export declare function ManageProvidersLink(): import("react").JSX.Element | null;
|
|
25
28
|
export declare function ConnectToolsLink(): import("react").JSX.Element | null;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { IoSettingsOutline } from "../../icons/io5/IoSettingsOutline.js";
|
|
1
2
|
import { PiPlugsConnectedFill } from "../../icons/pi/PiPlugsConnectedFill.js";
|
|
2
3
|
import { useChatConfig } from "../core/config.js";
|
|
3
4
|
import AllocationSelector from "./AllocationSelector.js";
|
|
@@ -8,7 +9,7 @@ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
|
8
9
|
* it: the machine, the workspace, and whatever else names the place. */
|
|
9
10
|
function ComposerContext({ children }) {
|
|
10
11
|
return /* @__PURE__ */ jsx("div", {
|
|
11
|
-
className: "mb-1.5 flex flex-wrap items-center gap-1.5",
|
|
12
|
+
className: "mb-1.5 flex min-h-7 flex-wrap items-center gap-1.5",
|
|
12
13
|
children
|
|
13
14
|
});
|
|
14
15
|
}
|
|
@@ -45,6 +46,24 @@ function ComposerControls({ targetSession }) {
|
|
|
45
46
|
targetSession
|
|
46
47
|
}), /* @__PURE__ */ jsx(AllocationSelector, { variant: "bare" })] });
|
|
47
48
|
}
|
|
49
|
+
/** Where the reader manages the providers behind the model picker, at the
|
|
50
|
+
* foot of a conversation list. */
|
|
51
|
+
function ManageProvidersLink() {
|
|
52
|
+
const { extraLinks, LinkComponent, strings } = useChatConfig();
|
|
53
|
+
if (!extraLinks.manageProviders) return null;
|
|
54
|
+
return /* @__PURE__ */ jsxs(LinkComponent, {
|
|
55
|
+
target: {
|
|
56
|
+
kind: "external",
|
|
57
|
+
href: extraLinks.manageProviders
|
|
58
|
+
},
|
|
59
|
+
className: "flex min-w-0 items-center gap-2 rounded-md px-2 py-1.5 text-xs theme-muted-text transition-colors hover:chat-tint hover:theme-text",
|
|
60
|
+
title: strings.sidebar.manageProviders,
|
|
61
|
+
children: [/* @__PURE__ */ jsx(IoSettingsOutline, { className: "h-3.5 w-3.5 shrink-0" }), /* @__PURE__ */ jsx("span", {
|
|
62
|
+
className: "truncate",
|
|
63
|
+
children: strings.sidebar.manageProviders
|
|
64
|
+
})]
|
|
65
|
+
});
|
|
66
|
+
}
|
|
48
67
|
function ConnectToolsLink() {
|
|
49
68
|
const { extraLinks, LinkComponent, strings } = useChatConfig();
|
|
50
69
|
if (!extraLinks.connectTools) return null;
|
|
@@ -58,4 +77,4 @@ function ConnectToolsLink() {
|
|
|
58
77
|
});
|
|
59
78
|
}
|
|
60
79
|
//#endregion
|
|
61
|
-
export { ComposerContext, ComposerControls, ComposerSettings, ComposerUsage, ConnectToolsLink };
|
|
80
|
+
export { ComposerContext, ComposerControls, ComposerSettings, ComposerUsage, ConnectToolsLink, ManageProvidersLink };
|
|
@@ -291,6 +291,12 @@ function ConfirmApproval({ part, onAnswer }) {
|
|
|
291
291
|
const t = strings.agentTranscript;
|
|
292
292
|
const [feedback, setFeedback] = useState(null);
|
|
293
293
|
const answer = (a) => onAnswer?.(part.id, a);
|
|
294
|
+
const [allowLabel, denyLabel] = {
|
|
295
|
+
command: [t.allowOnce, t.deny],
|
|
296
|
+
code: [t.allowCode, t.denyCode],
|
|
297
|
+
path: [t.allowPath, t.denyPath],
|
|
298
|
+
call: [t.allowCall, t.denyCall]
|
|
299
|
+
}[part.subject ?? "command"];
|
|
294
300
|
return /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
295
301
|
part.command && /* @__PURE__ */ jsx("pre", {
|
|
296
302
|
className: "overflow-x-auto rounded-md bg-(--theme-muted-panel-bg) p-2 font-mono text-xs whitespace-pre-wrap",
|
|
@@ -313,7 +319,7 @@ function ConfirmApproval({ part, onAnswer }) {
|
|
|
313
319
|
allowed: true
|
|
314
320
|
}),
|
|
315
321
|
className: "px-3 py-1 text-xs font-medium rounded-full bg-(--theme-element) text-(--theme-element-text)",
|
|
316
|
-
children:
|
|
322
|
+
children: allowLabel
|
|
317
323
|
}),
|
|
318
324
|
part.canAllowDirectory !== false && /* @__PURE__ */ jsx("button", {
|
|
319
325
|
type: "button",
|
|
@@ -332,7 +338,7 @@ function ConfirmApproval({ part, onAnswer }) {
|
|
|
332
338
|
allowed: false
|
|
333
339
|
}),
|
|
334
340
|
className: "px-3 py-1 text-xs font-medium rounded-full border theme-border hover:theme-hover text-red-600",
|
|
335
|
-
children:
|
|
341
|
+
children: denyLabel
|
|
336
342
|
}),
|
|
337
343
|
/* @__PURE__ */ jsx("button", {
|
|
338
344
|
type: "button",
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
import { type OpenMenu, type RowMenuItem } from '../../list/index.js';
|
|
3
|
+
import type { ConversationSummary } from '../types.js';
|
|
4
|
+
export type ConversationGroupKey = 'groupToday' | 'groupYesterday' | 'groupThisWeek' | 'groupThisMonth' | 'groupOlder';
|
|
5
|
+
/** Conversations by how long ago they started, newest group first, leaving
|
|
6
|
+
* out the groups with none. Each key names its label in the sidebar strings. */
|
|
7
|
+
export declare function groupConversationsByDate<T extends {
|
|
8
|
+
createdAt: string;
|
|
9
|
+
}>(conversations: T[]): {
|
|
10
|
+
key: ConversationGroupKey;
|
|
11
|
+
items: T[];
|
|
12
|
+
}[];
|
|
13
|
+
/** What a conversation row offers behind its menu (rename, share, download,
|
|
14
|
+
* delete) and the menu and dialogs that carry them out, for any list of
|
|
15
|
+
* conversations. Render `overlays` once beside the list. */
|
|
16
|
+
export declare function useConversationActions({ menuZClassName, }?: {
|
|
17
|
+
/** The menu's stacking class, for a list inside a layer above the page. */
|
|
18
|
+
menuZClassName?: string;
|
|
19
|
+
}): {
|
|
20
|
+
menuItems: (conv: ConversationSummary) => RowMenuItem[];
|
|
21
|
+
openMenu: OpenMenu;
|
|
22
|
+
overlays: ReactNode;
|
|
23
|
+
};
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { BiSolidTrashAlt } from "../../icons/bi/BiSolidTrashAlt.js";
|
|
2
|
+
import { FaCloudDownloadAlt } from "../../icons/fa/FaCloudDownloadAlt.js";
|
|
3
|
+
import { FaEdit } from "../../icons/fa/FaEdit.js";
|
|
4
|
+
import { PiShareBold } from "../../icons/pi/PiShareBold.js";
|
|
5
|
+
import { useRowMenu } from "../../list/RowContextMenu.js";
|
|
6
|
+
import { useChatConfig } from "../core/config.js";
|
|
7
|
+
import { useChat } from "../core/ChatProvider.js";
|
|
8
|
+
import { useRowDialogs } from "../ui/sidebar.js";
|
|
9
|
+
import { conversationToMarkdown, downloadText, exportFilename } from "../core/exportConversation.js";
|
|
10
|
+
import ShareDialog from "./ShareDialog.js";
|
|
11
|
+
import { useState } from "react";
|
|
12
|
+
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
13
|
+
import { DateTime } from "luxon";
|
|
14
|
+
//#region src/ai/components/conversationActions.tsx
|
|
15
|
+
/** Conversations by how long ago they started, newest group first, leaving
|
|
16
|
+
* out the groups with none. Each key names its label in the sidebar strings. */
|
|
17
|
+
function groupConversationsByDate(conversations) {
|
|
18
|
+
const now = DateTime.now();
|
|
19
|
+
const groups = {
|
|
20
|
+
groupToday: [],
|
|
21
|
+
groupYesterday: [],
|
|
22
|
+
groupThisWeek: [],
|
|
23
|
+
groupThisMonth: [],
|
|
24
|
+
groupOlder: []
|
|
25
|
+
};
|
|
26
|
+
for (const conv of conversations) {
|
|
27
|
+
const days = now.diff(DateTime.fromISO(conv.createdAt), "days").days;
|
|
28
|
+
groups[days < 1 ? "groupToday" : days < 2 ? "groupYesterday" : days < 7 ? "groupThisWeek" : days < 30 ? "groupThisMonth" : "groupOlder"].push(conv);
|
|
29
|
+
}
|
|
30
|
+
return Object.entries(groups).filter(([, items]) => items.length > 0).map(([key, items]) => ({
|
|
31
|
+
key,
|
|
32
|
+
items
|
|
33
|
+
}));
|
|
34
|
+
}
|
|
35
|
+
/** What a conversation row offers behind its menu (rename, share, download,
|
|
36
|
+
* delete) and the menu and dialogs that carry them out, for any list of
|
|
37
|
+
* conversations. Render `overlays` once beside the list. */
|
|
38
|
+
function useConversationActions({ menuZClassName } = {}) {
|
|
39
|
+
const { strings } = useChatConfig();
|
|
40
|
+
const t = strings.sidebar;
|
|
41
|
+
const { adapter, notify, deleteConversation, updateConversationTitle } = useChat();
|
|
42
|
+
const { openMenu, contextMenu } = useRowMenu(menuZClassName);
|
|
43
|
+
const [sharing, setSharing] = useState(null);
|
|
44
|
+
const { requestDelete, requestRename, dialogs } = useRowDialogs({
|
|
45
|
+
strings: {
|
|
46
|
+
deleteTitle: t.deleteTitle,
|
|
47
|
+
deleteBody: () => t.deleteBody,
|
|
48
|
+
deleteAction: t.deleteAction,
|
|
49
|
+
renameTitle: t.renameTitle,
|
|
50
|
+
renameLabel: t.renameLabel,
|
|
51
|
+
renamePlaceholder: t.renamePlaceholder,
|
|
52
|
+
renameAction: t.renameAction
|
|
53
|
+
},
|
|
54
|
+
nameOf: (conv) => conv.title || t.untitled,
|
|
55
|
+
onDelete: (conv) => deleteConversation(conv.id),
|
|
56
|
+
onRename: (conv, title) => updateConversationTitle(conv.id, title)
|
|
57
|
+
});
|
|
58
|
+
const download = async (id) => {
|
|
59
|
+
try {
|
|
60
|
+
const conversation = await adapter.conversations.get(id);
|
|
61
|
+
downloadText(exportFilename(conversation.title), conversationToMarkdown(conversation));
|
|
62
|
+
} catch {
|
|
63
|
+
notify.error(strings.chrome.exportError);
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
const menuItems = (conv) => [
|
|
67
|
+
{
|
|
68
|
+
kind: "action",
|
|
69
|
+
label: t.rename,
|
|
70
|
+
icon: /* @__PURE__ */ jsx(FaEdit, {}),
|
|
71
|
+
onSelect: () => requestRename(conv)
|
|
72
|
+
},
|
|
73
|
+
...adapter.sharing && conv.isOwner !== false ? [{
|
|
74
|
+
kind: "action",
|
|
75
|
+
label: t.share,
|
|
76
|
+
icon: /* @__PURE__ */ jsx(PiShareBold, {}),
|
|
77
|
+
onSelect: () => setSharing(conv.id)
|
|
78
|
+
}] : [],
|
|
79
|
+
{
|
|
80
|
+
kind: "action",
|
|
81
|
+
label: strings.chrome.download,
|
|
82
|
+
icon: /* @__PURE__ */ jsx(FaCloudDownloadAlt, {}),
|
|
83
|
+
onSelect: () => void download(conv.id)
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
kind: "action",
|
|
87
|
+
label: t.delete,
|
|
88
|
+
icon: /* @__PURE__ */ jsx(BiSolidTrashAlt, {}),
|
|
89
|
+
destructive: true,
|
|
90
|
+
onSelect: () => requestDelete(conv)
|
|
91
|
+
}
|
|
92
|
+
];
|
|
93
|
+
return {
|
|
94
|
+
menuItems,
|
|
95
|
+
openMenu,
|
|
96
|
+
overlays: /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
97
|
+
contextMenu,
|
|
98
|
+
dialogs,
|
|
99
|
+
sharing && /* @__PURE__ */ jsx(ShareDialog, {
|
|
100
|
+
conversationId: sharing,
|
|
101
|
+
isOpen: true,
|
|
102
|
+
onClose: () => setSharing(null)
|
|
103
|
+
})
|
|
104
|
+
] })
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
//#endregion
|
|
108
|
+
export { groupConversationsByDate, useConversationActions };
|
package/dist/ai/index.d.ts
CHANGED
|
@@ -15,9 +15,10 @@ export { CHAT_COLUMN_SCOPE, ConversationLayout, DRAWER_BELOW_PX, default as Chat
|
|
|
15
15
|
export { default as ChatMessageView } from './components/ChatMessage.js';
|
|
16
16
|
export { default as ChatMessageList } from './components/ChatMessageList.js';
|
|
17
17
|
export { default as ChatSidebar } from './components/ChatSidebar.js';
|
|
18
|
+
export { default as ChatStage } from './components/ChatStage.js';
|
|
18
19
|
export { default as ChatThread } from './components/ChatThread.js';
|
|
19
|
-
export { ComposerContext, ComposerControls, ComposerSettings, ComposerUsage, ConnectToolsLink, } from './components/ComposerChrome.js';
|
|
20
|
-
export {
|
|
20
|
+
export { ComposerContext, ComposerControls, ComposerSettings, ComposerUsage, ConnectToolsLink, ManageProvidersLink, } from './components/ComposerChrome.js';
|
|
21
|
+
export { type ConversationGroupKey, groupConversationsByDate, useConversationActions, } from './components/conversationActions.js';
|
|
21
22
|
export { default as DragOverlay } from './components/DragOverlay.js';
|
|
22
23
|
export { default as ModelSelector, getProviderKeyFromModelId, } from './components/ModelSelector.js';
|
|
23
24
|
export { default as ProviderIssueBanner } from './components/ProviderIssueBanner.js';
|
|
@@ -42,5 +43,5 @@ export * from './types.js';
|
|
|
42
43
|
export { ConversationSidebar, type ConversationSidebarGroup, useResizableSidebarWidth, } from './ui/ConversationSidebar.js';
|
|
43
44
|
export { type DropdownOption, default as Dropdown } from './ui/Dropdown.js';
|
|
44
45
|
export { NoticeBar, NoticeCard, type NoticeTone, OutputCard } from './ui/Notice.js';
|
|
45
|
-
export { RenameDialog, type RowDialogStrings, SidebarDrawer, SidebarGroupHeading, SidebarPanel, SidebarRailItem, SidebarRow, SidebarToggle, useRowDialogs, } from './ui/sidebar.js';
|
|
46
|
+
export { RenameDialog, type RowDialogStrings, SidebarDrawer, SidebarGroupHeading, SidebarPanel, SidebarPlaceholder, SidebarRailItem, SidebarRow, SidebarToggle, useRowDialogs, } from './ui/sidebar.js';
|
|
46
47
|
export { formatFileSize, isMac, isOrgModel } from './utils.js';
|
package/dist/ai/index.js
CHANGED
|
@@ -25,24 +25,25 @@ import BlockedGroupBanner from "./components/BlockedGroupBanner.js";
|
|
|
25
25
|
import BranchNavigator from "./components/BranchNavigator.js";
|
|
26
26
|
import { getGreeting } from "./core/greeting.js";
|
|
27
27
|
import useDragDrop from "./core/useDragDrop.js";
|
|
28
|
-
import {
|
|
28
|
+
import { NoticeBar, NoticeCard, OutputCard } from "./ui/Notice.js";
|
|
29
|
+
import { ComposerContext, ComposerControls, ComposerSettings, ComposerUsage, ConnectToolsLink, ManageProvidersLink } from "./components/ComposerChrome.js";
|
|
29
30
|
import DragOverlay from "./components/DragOverlay.js";
|
|
30
31
|
import { pasteInlineMaxBytes } from "./core/pastes.js";
|
|
31
32
|
import { slashMatches } from "./components/SlashMenu.js";
|
|
32
33
|
import ChatInput from "./components/ChatInput.js";
|
|
34
|
+
import ChatStage from "./components/ChatStage.js";
|
|
33
35
|
import ProviderIssueBanner from "./components/ProviderIssueBanner.js";
|
|
34
36
|
import ChatEmptyState from "./components/ChatEmptyState.js";
|
|
35
37
|
import { FOCUS_SIDEBAR_SEARCH_EVENT } from "./core/events.js";
|
|
36
38
|
import { useKeyboardShortcuts } from "./core/useKeyboardShortcuts.js";
|
|
37
39
|
import { KeyboardShortcutsProvider } from "./core/KeyboardShortcutsProvider.js";
|
|
38
|
-
import { RenameDialog, SidebarDrawer, SidebarGroupHeading, SidebarPanel, SidebarRailItem, SidebarRow, SidebarToggle, useRowDialogs } from "./ui/sidebar.js";
|
|
40
|
+
import { RenameDialog, SidebarDrawer, SidebarGroupHeading, SidebarPanel, SidebarPlaceholder, SidebarRailItem, SidebarRow, SidebarToggle, useRowDialogs } from "./ui/sidebar.js";
|
|
39
41
|
import { ConversationSidebar, useResizableSidebarWidth } from "./ui/ConversationSidebar.js";
|
|
40
42
|
import ShareDialog, { ShareButton } from "./components/ShareDialog.js";
|
|
43
|
+
import { groupConversationsByDate, useConversationActions } from "./components/conversationActions.js";
|
|
41
44
|
import ChatSidebar from "./components/ChatSidebar.js";
|
|
42
45
|
import ChatLayout, { CHAT_COLUMN_SCOPE, ConversationLayout, DRAWER_BELOW_PX } from "./components/ChatLayout.js";
|
|
43
46
|
import ChatMessage_default from "./components/ChatMessage.js";
|
|
44
47
|
import ChatMessageList from "./components/ChatMessageList.js";
|
|
45
48
|
import ChatThread from "./components/ChatThread.js";
|
|
46
|
-
|
|
47
|
-
import { NoticeBar, NoticeCard, OutputCard } from "./ui/Notice.js";
|
|
48
|
-
export { AGENT_COLOR_NAMES, ActivityLine, AgentMessageParts, AllocationSelector, ApprovalBlock, AttachmentManager, AttachmentUpload, BlockedGroupBanner, BranchNavigator, CHAT_COLUMN_SCOPE, ChatAdapterError, ChatEmptyState, ChatInput, ChatLayout, ChatMessageList, ChatMessage_default as ChatMessageView, ChatProvider, ChatSidebar, ChatThread, ComposerContext, ComposerControls, ComposerFrame, ComposerSettings, ComposerUsage, ConnectToolsLink, ConversationLayout, ConversationSidebar, DEFAULT_PERMISSION_MODE, DRAWER_BELOW_PX, DragOverlay, Dropdown, FOCUS_SIDEBAR_SEARCH_EVENT, INTERRUPTED_NOTICE, KeyboardShortcutsProvider, MAX_EDIT_DIFF_LINES, MAX_WRITE_DIFF_LINES, ModelSelector, NAMED_PERMISSION_MODES, NoticeBar, NoticeCard, OutputCard, PermissionPicker, ProviderIssueBanner, RenameDialog, ShareButton, ShareDialog, SidebarDrawer, SidebarGroupHeading, SidebarPanel, SidebarRailItem, SidebarRow, SidebarToggle, agentColorHex, agentTypeLabel, applyPartDelta, askQuestionFromArgs, bashExitCode, chatReducer, clampPermissionMode, classifyPseudoUserMessage, clip, compactCount, computeEditDiff, computeWriteRows, defaultChatStrings, durationToAbsHumanDuration, editSummary, finalizeParts, firstNonEmptyLine, formatElapsed, formatFileSize, fullToolArgs, getGreeting, getProviderKeyFromModelId, hiddenTranscriptTool, initialState, interruptionNotice, isEditDiffTool, isGroupableTool, isMac, isNamedPermissionMode, isOrgModel, languageForPath, lineDelta, parseEditArgs, parseSubagentNotice, pasteInlineMaxBytes, permissionModesUpTo, planFromArgs, plural, providerIssueFor, resolveChatConfig, resultFailed, rollupSentence, sanitizeLabel, sanitizePanelText, slashMatches, subagentDeliveryLine, summarizeToolArgs, taskCallFromArgs, thinkingHeading, tokenizeDiffLines, toolHeaderFor, toolSummary, useChat, useChatConfig, useDragDrop, useKeyboardShortcuts, useResizableSidebarWidth, useRowDialogs, wordEmphasisRanges };
|
|
49
|
+
export { AGENT_COLOR_NAMES, ActivityLine, AgentMessageParts, AllocationSelector, ApprovalBlock, AttachmentManager, AttachmentUpload, BlockedGroupBanner, BranchNavigator, CHAT_COLUMN_SCOPE, ChatAdapterError, ChatEmptyState, ChatInput, ChatLayout, ChatMessageList, ChatMessage_default as ChatMessageView, ChatProvider, ChatSidebar, ChatStage, ChatThread, ComposerContext, ComposerControls, ComposerSettings, ComposerUsage, ConnectToolsLink, ConversationLayout, ConversationSidebar, DEFAULT_PERMISSION_MODE, DRAWER_BELOW_PX, DragOverlay, Dropdown, FOCUS_SIDEBAR_SEARCH_EVENT, INTERRUPTED_NOTICE, KeyboardShortcutsProvider, MAX_EDIT_DIFF_LINES, MAX_WRITE_DIFF_LINES, ManageProvidersLink, ModelSelector, NAMED_PERMISSION_MODES, NoticeBar, NoticeCard, OutputCard, PermissionPicker, ProviderIssueBanner, RenameDialog, ShareButton, ShareDialog, SidebarDrawer, SidebarGroupHeading, SidebarPanel, SidebarPlaceholder, SidebarRailItem, SidebarRow, SidebarToggle, agentColorHex, agentTypeLabel, applyPartDelta, askQuestionFromArgs, bashExitCode, chatReducer, clampPermissionMode, classifyPseudoUserMessage, clip, compactCount, computeEditDiff, computeWriteRows, defaultChatStrings, durationToAbsHumanDuration, editSummary, finalizeParts, firstNonEmptyLine, formatElapsed, formatFileSize, fullToolArgs, getGreeting, getProviderKeyFromModelId, groupConversationsByDate, hiddenTranscriptTool, initialState, interruptionNotice, isEditDiffTool, isGroupableTool, isMac, isNamedPermissionMode, isOrgModel, languageForPath, lineDelta, parseEditArgs, parseSubagentNotice, pasteInlineMaxBytes, permissionModesUpTo, planFromArgs, plural, providerIssueFor, resolveChatConfig, resultFailed, rollupSentence, sanitizeLabel, sanitizePanelText, slashMatches, subagentDeliveryLine, summarizeToolArgs, taskCallFromArgs, thinkingHeading, tokenizeDiffLines, toolHeaderFor, toolSummary, useChat, useChatConfig, useConversationActions, useDragDrop, useKeyboardShortcuts, useResizableSidebarWidth, useRowDialogs, wordEmphasisRanges };
|
package/dist/ai/strings.d.ts
CHANGED
|
@@ -143,6 +143,7 @@ export interface ChatStrings {
|
|
|
143
143
|
download: string;
|
|
144
144
|
exportError: string;
|
|
145
145
|
jumpToLatest: string;
|
|
146
|
+
dismiss: string;
|
|
146
147
|
};
|
|
147
148
|
messageMeta: {
|
|
148
149
|
stopped: string;
|
|
@@ -182,6 +183,12 @@ export interface ChatStrings {
|
|
|
182
183
|
allowOnce: string;
|
|
183
184
|
allowDirectory: string;
|
|
184
185
|
deny: string;
|
|
186
|
+
allowCode: string;
|
|
187
|
+
denyCode: string;
|
|
188
|
+
allowPath: string;
|
|
189
|
+
denyPath: string;
|
|
190
|
+
allowCall: string;
|
|
191
|
+
denyCall: string;
|
|
185
192
|
denyWithFeedback: string;
|
|
186
193
|
feedbackPlaceholder: string;
|
|
187
194
|
send: string;
|
package/dist/ai/strings.js
CHANGED
|
@@ -142,7 +142,8 @@ var defaultChatStrings = {
|
|
|
142
142
|
noMatches: "No conversations match your search",
|
|
143
143
|
download: "Download",
|
|
144
144
|
exportError: "Failed to export conversation",
|
|
145
|
-
jumpToLatest: "Jump to latest"
|
|
145
|
+
jumpToLatest: "Jump to latest",
|
|
146
|
+
dismiss: "Dismiss"
|
|
146
147
|
},
|
|
147
148
|
messageMeta: {
|
|
148
149
|
stopped: "Stopped",
|
|
@@ -182,6 +183,12 @@ var defaultChatStrings = {
|
|
|
182
183
|
allowOnce: "Yes, allow this command",
|
|
183
184
|
allowDirectory: "Yes, and allow this directory for the session",
|
|
184
185
|
deny: "No, deny this command",
|
|
186
|
+
allowCode: "Yes, run this code",
|
|
187
|
+
denyCode: "No, don't run this code",
|
|
188
|
+
allowPath: "Yes, allow this once",
|
|
189
|
+
denyPath: "No, deny",
|
|
190
|
+
allowCall: "Yes, allow this call",
|
|
191
|
+
denyCall: "No, deny this call",
|
|
185
192
|
denyWithFeedback: "No, and provide feedback to the agent",
|
|
186
193
|
feedbackPlaceholder: "Tell the agent what to do instead…",
|
|
187
194
|
send: "Send",
|
package/dist/ai/types.d.ts
CHANGED
|
@@ -84,11 +84,13 @@ export type ApprovalAnswerValue = {
|
|
|
84
84
|
text: string;
|
|
85
85
|
chat?: boolean;
|
|
86
86
|
};
|
|
87
|
+
export type ApprovalSubject = 'command' | 'code' | 'path' | 'call';
|
|
87
88
|
export interface ApprovalPart {
|
|
88
89
|
kind: 'approval';
|
|
89
90
|
id: string;
|
|
90
91
|
approvalKind: 'confirm' | 'ask' | 'plan';
|
|
91
92
|
toolName?: string;
|
|
93
|
+
subject?: ApprovalSubject;
|
|
92
94
|
command?: string;
|
|
93
95
|
reason?: string;
|
|
94
96
|
agent?: string;
|
|
@@ -27,9 +27,10 @@ export declare function ConversationSidebar<T>({ label, collapsed: collapsedProp
|
|
|
27
27
|
open: string;
|
|
28
28
|
close: string;
|
|
29
29
|
};
|
|
30
|
-
/** Omit for a fixed width.
|
|
30
|
+
/** Omit for a fixed width. A `storageKey` keeps this list's width apart
|
|
31
|
+
* from the others'. */
|
|
31
32
|
resize?: {
|
|
32
|
-
storageKey
|
|
33
|
+
storageKey?: string;
|
|
33
34
|
label: string;
|
|
34
35
|
hint: string;
|
|
35
36
|
};
|
|
@@ -3,6 +3,7 @@ import { SidebarDrawer, SidebarGroupHeading, SidebarPanel, SidebarToggle } from
|
|
|
3
3
|
import cx from "classnames";
|
|
4
4
|
import { Fragment, useEffect, useRef, useState } from "react";
|
|
5
5
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
var SHARED_WIDTH_STORAGE_KEY = "aiChatSidebarWidth";
|
|
6
7
|
function clampSidebarWidth(width) {
|
|
7
8
|
return Math.min(480, Math.max(200, width));
|
|
8
9
|
}
|
|
@@ -91,7 +92,7 @@ function useItemCycling(ordered, cycle) {
|
|
|
91
92
|
* collapse to a rail, with an optional drag handle for the width. The host
|
|
92
93
|
* decides what is listed, how it is grouped and how each row reads. */
|
|
93
94
|
function ConversationSidebar({ label, collapsed: collapsedProp, onToggle, toggleLabels, resize, fill: fillProp = false, drawer, groups, getKey, renderRow, loading = false, placeholder, top, rail, footer, cycle, groupTestId, children }) {
|
|
94
|
-
const sized = useResizableSidebarWidth(resize?.storageKey ??
|
|
95
|
+
const sized = useResizableSidebarWidth(resize?.storageKey ?? SHARED_WIDTH_STORAGE_KEY);
|
|
95
96
|
useItemCycling(groups.flatMap((g) => g.items), cycle);
|
|
96
97
|
const fill = fillProp || !!drawer;
|
|
97
98
|
const collapsed = collapsedProp && !fill;
|
package/dist/ai/ui/sidebar.d.ts
CHANGED
|
@@ -37,6 +37,12 @@ export declare function SidebarGroupHeading({ children, tone, testId, }: {
|
|
|
37
37
|
tone?: 'default' | 'attention';
|
|
38
38
|
testId?: string | undefined;
|
|
39
39
|
}): import("react").JSX.Element;
|
|
40
|
+
/** What a list says in place of its rows: none yet, no matches, or why it
|
|
41
|
+
* could not load. Plain text, so an empty list reads the same in every list. */
|
|
42
|
+
export declare function SidebarPlaceholder({ children, testId, }: {
|
|
43
|
+
children: ReactNode;
|
|
44
|
+
testId?: string | undefined;
|
|
45
|
+
}): import("react").JSX.Element;
|
|
40
46
|
/** One entry in the list: the row highlights while it is the open one or
|
|
41
47
|
* while its menu is up, and the menu opens from its button or a right-click. */
|
|
42
48
|
export declare function SidebarRow({ selected, menuItems, openMenu, className, children, }: {
|
package/dist/ai/ui/sidebar.js
CHANGED
|
@@ -76,6 +76,15 @@ function SidebarGroupHeading({ children, tone = "default", testId }) {
|
|
|
76
76
|
children
|
|
77
77
|
});
|
|
78
78
|
}
|
|
79
|
+
/** What a list says in place of its rows: none yet, no matches, or why it
|
|
80
|
+
* could not load. Plain text, so an empty list reads the same in every list. */
|
|
81
|
+
function SidebarPlaceholder({ children, testId }) {
|
|
82
|
+
return /* @__PURE__ */ jsx("p", {
|
|
83
|
+
"data-testid": testId,
|
|
84
|
+
className: "px-2 pt-1 text-sm theme-muted-text",
|
|
85
|
+
children
|
|
86
|
+
});
|
|
87
|
+
}
|
|
79
88
|
/** One entry in the list: the row highlights while it is the open one or
|
|
80
89
|
* while its menu is up, and the menu opens from its button or a right-click. */
|
|
81
90
|
function SidebarRow({ selected, menuItems, openMenu, className, children }) {
|
|
@@ -182,4 +191,4 @@ function useRowDialogs({ strings, nameOf, onDelete, onRename }) {
|
|
|
182
191
|
};
|
|
183
192
|
}
|
|
184
193
|
//#endregion
|
|
185
|
-
export { RenameDialog, SidebarDrawer, SidebarGroupHeading, SidebarPanel, SidebarRailItem, SidebarRow, SidebarToggle, useRowDialogs };
|
|
194
|
+
export { RenameDialog, SidebarDrawer, SidebarGroupHeading, SidebarPanel, SidebarPlaceholder, SidebarRailItem, SidebarRow, SidebarToggle, useRowDialogs };
|