@nextclaw/ui 0.15.1 → 0.15.3
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/CHANGELOG.md +51 -0
- package/dist/assets/{api-b1R9VdeH.js → api-iNBpppzj.js} +3 -3
- package/dist/assets/{appearance-settings-page-D2O9pch9.js → appearance-settings-page-DMffQFR3.js} +1 -1
- package/dist/assets/{book-open-B77lQ2Tg.js → book-open-C3mJGwiy.js} +1 -1
- package/dist/assets/channels-list-page-CCtp0BRS.js +8 -0
- package/dist/assets/chat-page-H5a0dWvO.js +1 -0
- package/dist/assets/config-split-page-CrOJgB-Y.js +1 -0
- package/dist/assets/{confirm-dialog-C-NXSioX.js → confirm-dialog-Chv50USy.js} +2 -2
- package/dist/assets/{desktop-update-config-usHpXugP.js → desktop-update-config-KzTuXRf_.js} +1 -1
- package/dist/assets/{dist-jdGmbb6w.js → dist-BunzmC4B.js} +1 -1
- package/dist/assets/{dist-YtoqU-AT.js → dist-ChmGwvtK.js} +1 -1
- package/dist/assets/doc-browser-DNRL4Zvd.js +1 -0
- package/dist/assets/doc-browser-Dg0pmkOg.js +1 -0
- package/dist/assets/doc-browser-context-BHY-0FSD.js +1 -0
- package/dist/assets/{es2015-bNpL2LKy.js → es2015-DQZ5JWwK.js} +1 -1
- package/dist/assets/{external-link-BM6fk8q-.js → external-link-CU0kzzIP.js} +1 -1
- package/dist/assets/form-actions-BvCp_0lS.js +1 -0
- package/dist/assets/{i18n-provider-CntWolRA.js → i18n-provider-Cu8XyZb_.js} +1 -1
- package/dist/assets/index-CzfBdvK1.css +1 -0
- package/dist/assets/index-DGqHne1Q.js +104 -0
- package/dist/assets/loader-circle-CDSFuzmk.js +1 -0
- package/dist/assets/mcp-marketplace-page-BeEQK0DL.js +9 -0
- package/dist/assets/mcp-marketplace-page-D6idOTLp.js +1 -0
- package/dist/assets/model-config-page-bNNo-XyG.js +1 -0
- package/dist/assets/plus-D4DsdLN-.js +1 -0
- package/dist/assets/{provider-scoped-model-input-Cm_a4GHf.js → provider-scoped-model-input-IlgQCsoT.js} +1 -1
- package/dist/assets/providers-config-page-wLo6CAJw.js +1 -0
- package/dist/assets/{react-BN8uzPnp.js → react-BPIsQIlO.js} +1 -1
- package/dist/assets/{refresh-cw-BpVcFPmJ.js → refresh-cw-CILd1vAP.js} +1 -1
- package/dist/assets/remote-uKEYp7AR.js +1 -0
- package/dist/assets/rotate-cw-wPFPg1kH.js +1 -0
- package/dist/assets/runtime-config-page-DDn1sP4G.js +1 -0
- package/dist/assets/{save-BpFW5fpk.js → save-ByJqcPTP.js} +1 -1
- package/dist/assets/{search-D0uO7enf.js → search-DVIV6pfD.js} +1 -1
- package/dist/assets/search-config-page-B-Cf4iiB.js +1 -0
- package/dist/assets/secrets-config-page-DPKsY8Iw.js +3 -0
- package/dist/assets/security-config-e9SSBlKr.js +1 -0
- package/dist/assets/{select-Bh-CrA4p.js → select-BdgczSNw.js} +1 -1
- package/dist/assets/{setting-row-BJfCHRcb.js → setting-row-BkTVUTKx.js} +1 -1
- package/dist/assets/{settings-2-Blzi1vr6.js → settings-2-CH5shGg_.js} +1 -1
- package/dist/assets/{side-dock-ZdaSrQVB.js → side-dock-BsBvcJ9i.js} +2 -2
- package/dist/assets/{skeleton-BLlEzebZ.js → skeleton-DeX1FKw7.js} +1 -1
- package/dist/assets/switch-Cv8Ekb3x.js +1 -0
- package/dist/assets/{tag-chip-CzGihiQx.js → tag-chip-RB9uKcoC.js} +1 -1
- package/dist/assets/{tooltip-CdcrBjrC.js → tooltip-oQlEN-l6.js} +1 -1
- package/dist/assets/{use-config-CVPgsBmU.js → use-config-l3W7y8Qz.js} +1 -1
- package/dist/assets/{use-confirm-dialog-CSeBk9SF.js → use-confirm-dialog-BAxaVOJI.js} +1 -1
- package/dist/assets/x-BBMffEN0.js +1 -0
- package/dist/index.html +38 -30
- package/index.html +12 -4
- package/package.json +9 -9
- package/src/app/components/layout/__tests__/sidebar.layout.test.tsx +29 -1
- package/src/app/components/layout/sidebar-items.tsx +46 -7
- package/src/app/components/layout/sidebar-rail.styles.ts +2 -2
- package/src/app/components/layout/sidebar.tsx +84 -62
- package/src/app/configs/app-navigation.config.ts +49 -0
- package/src/app/styles/design-system.css +99 -4
- package/src/features/channels/components/config/channel-form.tsx +14 -11
- package/src/features/chat/components/conversation/__tests__/chat-conversation-header-section.test.tsx +40 -0
- package/src/features/chat/components/conversation/chat-conversation-header-section.tsx +3 -1
- package/src/features/chat/components/conversation/chat-conversation-panel.tsx +1 -1
- package/src/features/chat/components/layout/__tests__/chat-sidebar-toolbar.test.tsx +48 -0
- package/src/features/chat/components/layout/__tests__/chat-sidebar-utility-menu.test.tsx +55 -0
- package/src/features/chat/components/layout/chat-sidebar-desktop-layout.tsx +0 -3
- package/src/features/chat/components/layout/chat-sidebar-toolbar.tsx +3 -4
- package/src/features/chat/components/layout/chat-sidebar-utility-menu.tsx +30 -31
- package/src/features/chat/components/layout/chat-sidebar.tsx +21 -7
- package/src/features/chat/features/conversation/components/session-conversation-input.tsx +2 -1
- package/src/features/chat/features/conversation/components/session-queued-input-rows.tsx +1 -1
- package/src/features/chat/features/message/components/__tests__/chat-inline-panel-app-card.test.tsx +22 -1
- package/src/features/chat/features/message/components/__tests__/chat-message-list.container.test.tsx +62 -1
- package/src/features/chat/features/message/components/chat-inline-panel-app-card.tsx +10 -5
- package/src/features/chat/features/message/components/chat-message-list.container.tsx +47 -1
- package/src/features/chat/features/message/utils/__tests__/chat-message-process-summary.utils.test.ts +11 -1
- package/src/features/chat/features/message/utils/__tests__/chat-message-texts.utils.test.ts +23 -0
- package/src/features/chat/features/message/utils/chat-inline-panel-app-card.utils.ts +0 -11
- package/src/features/chat/features/message/utils/chat-message-process-summary.utils.ts +5 -0
- package/src/features/chat/features/message/utils/chat-message-texts.utils.ts +138 -0
- package/src/features/chat/features/session/components/__tests__/chat-sidebar-project-groups.test.tsx +116 -0
- package/src/features/chat/features/session/components/chat-sidebar-project-groups.tsx +108 -46
- package/src/features/chat/features/session/components/chat-sidebar-session-entry.tsx +6 -0
- package/src/features/chat/features/session/components/chat-sidebar-session-item.tsx +48 -24
- package/src/features/chat/features/session/components/chat-sidebar-session-list.tsx +0 -3
- package/src/features/chat/features/session/components/session-header/chat-session-header-actions.tsx +0 -4
- package/src/features/chat/features/session/components/session-header/chat-session-title-switcher.tsx +2 -2
- package/src/features/chat/features/session/utils/chat-sidebar-session-groups.utils.ts +25 -3
- package/src/features/chat/features/welcome/components/chat-welcome-capability-grid.tsx +9 -4
- package/src/features/chat/features/welcome/components/chat-welcome-project-picker.tsx +1 -1
- package/src/features/chat/features/welcome/components/chat-welcome-session-type-picker.tsx +1 -1
- package/src/features/chat/features/welcome/components/chat-welcome.tsx +0 -5
- package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-file-preview.test.tsx +226 -56
- package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-panel-content.test.tsx +1 -0
- package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-panel.test.tsx +144 -0
- package/src/features/chat/features/workspace/components/chat-session-workspace-directory-browser.tsx +99 -0
- package/src/features/chat/features/workspace/components/chat-session-workspace-file-breadcrumb-browser.tsx +2 -2
- package/src/features/chat/features/workspace/components/chat-session-workspace-file-breadcrumbs.tsx +4 -2
- package/src/features/chat/features/workspace/components/chat-session-workspace-file-preview.tsx +232 -21
- package/src/features/chat/features/workspace/components/chat-session-workspace-panel-content.tsx +3 -0
- package/src/features/chat/features/workspace/components/chat-session-workspace-panel-nav.tsx +44 -1
- package/src/features/chat/features/workspace/components/chat-session-workspace-panel.tsx +45 -3
- package/src/features/chat/features/workspace/utils/chat-workspace-file-tab-persistence.utils.ts +4 -0
- package/src/features/chat/managers/__tests__/chat-session-list.manager.test.ts +33 -2
- package/src/features/chat/managers/chat-session-list.manager.ts +32 -0
- package/src/features/chat/managers/chat-thread.manager.ts +2 -0
- package/src/features/chat/stores/chat-session-list.store.ts +28 -5
- package/src/features/chat/stores/chat-thread.store.ts +3 -0
- package/src/features/cron/components/cron-config.tsx +63 -80
- package/src/features/marketplace/components/detail-doc/__tests__/marketplace-detail-doc.test.tsx +44 -6
- package/src/features/marketplace/components/marketplace-detail-doc.tsx +8 -4
- package/src/features/marketplace/components/marketplace-page-parts.tsx +1 -1
- package/src/features/marketplace/components/mcp/mcp-marketplace-page.tsx +5 -12
- package/src/features/marketplace/hooks/use-marketplace-detail-doc-entry.ts +84 -0
- package/src/features/panel-apps/components/panel-app-list-item.tsx +6 -6
- package/src/features/panel-apps/components/panel-apps-list.tsx +2 -2
- package/src/features/panel-apps/index.ts +1 -0
- package/src/features/panel-apps/utils/panel-app-doc-browser.utils.tsx +2 -10
- package/src/features/panel-apps/utils/panel-app-iframe.utils.ts +6 -0
- package/src/features/pwa/managers/__tests__/pwa-shell-theme.manager.test.ts +11 -3
- package/src/features/pwa/managers/pwa-shell-theme.manager.ts +3 -1
- package/src/features/right-panel-resources/components/right-panel-resource-home-page.tsx +1 -1
- package/src/features/service-apps/components/service-apps-panel.tsx +145 -35
- package/src/features/settings/components/config/provider-auth-section.tsx +1 -1
- package/src/features/settings/components/config/provider-form.tsx +11 -8
- package/src/features/settings/components/config/provider-models-section.tsx +7 -7
- package/src/features/settings/components/config/provider-pill-selector.tsx +1 -1
- package/src/features/settings/components/config/secrets-config-form.tsx +5 -4
- package/src/features/settings/pages/model-config-page.tsx +26 -25
- package/src/features/settings/pages/providers-config-page.tsx +10 -13
- package/src/features/settings/pages/search-config-page.tsx +8 -5
- package/src/features/side-dock/components/side-dock.tsx +3 -3
- package/src/features/system-status/components/config/runtime-config-editor.tsx +5 -4
- package/src/index.css +257 -13
- package/src/shared/components/actions/action-link.tsx +1 -1
- package/src/shared/components/config-split-page.tsx +6 -6
- package/src/shared/components/doc-browser/__tests__/doc-browser-url.utils.test.ts +73 -0
- package/src/shared/components/doc-browser/__tests__/doc-browser.test.tsx +48 -0
- package/src/shared/components/doc-browser/doc-browser-context.tsx +4 -0
- package/src/shared/components/doc-browser/doc-browser-panel-parts.tsx +6 -2
- package/src/shared/components/doc-browser/doc-browser-renderer.types.ts +2 -1
- package/src/shared/components/doc-browser/doc-browser-tab-strip.tsx +10 -10
- package/src/shared/components/doc-browser/doc-browser.tsx +6 -4
- package/src/shared/components/doc-browser/utils/doc-browser-url.utils.ts +62 -4
- package/src/shared/components/resizable-right-panel/__tests__/resizable-right-panel.test.tsx +18 -0
- package/src/shared/components/resizable-right-panel/resizable-right-panel.tsx +28 -3
- package/src/shared/components/ui/actions/__tests__/icon-action-button.test.tsx +36 -0
- package/src/shared/components/ui/actions/form-actions.tsx +25 -0
- package/src/shared/components/ui/actions/icon-action-button.tsx +25 -2
- package/src/shared/components/ui/button.tsx +1 -1
- package/src/shared/components/ui/card.tsx +12 -4
- package/src/shared/components/ui/dialog.tsx +1 -1
- package/src/shared/components/ui/input.tsx +1 -1
- package/src/shared/components/ui/select.tsx +1 -1
- package/src/shared/components/ui/switch.tsx +1 -1
- package/src/shared/components/ui/tab-strip/compact-tab-strip.tsx +2 -1
- package/src/shared/components/ui/tabs.tsx +1 -1
- package/src/shared/components/ui/textarea.tsx +1 -1
- package/src/shared/hooks/use-server-path-browse.ts +26 -4
- package/src/shared/hooks/use-server-path-read.ts +11 -1
- package/src/shared/lib/api/utils/server-path.utils.ts +1 -0
- package/src/shared/lib/i18n/locales/en-US/chat.json +99 -0
- package/src/shared/lib/i18n/locales/en-US/core.json +3 -0
- package/src/shared/lib/i18n/locales/en-US/doc-browser.json +5 -0
- package/src/shared/lib/i18n/locales/zh-CN/chat.json +99 -0
- package/src/shared/lib/i18n/locales/zh-CN/core.json +3 -0
- package/src/shared/lib/i18n/locales/zh-CN/doc-browser.json +5 -0
- package/src/shared/lib/session-project/workspace-file-breadcrumb.utils.ts +9 -5
- package/src/shared/lib/theme/index.test.ts +21 -0
- package/src/shared/lib/theme/index.ts +6 -4
- package/src/vite-env.d.ts +2 -0
- package/dist/assets/channels-list-page-DcsIQc6A.js +0 -8
- package/dist/assets/chat-page-CZ7WxPir.js +0 -1
- package/dist/assets/config-split-page-BWQ6_Raq.js +0 -1
- package/dist/assets/doc-browser-B_Tf9n70.js +0 -1
- package/dist/assets/doc-browser-BdZPFOVa.js +0 -1
- package/dist/assets/doc-browser-context-DwokemUn.js +0 -1
- package/dist/assets/index-BIcEw90u.js +0 -104
- package/dist/assets/index-BiNSTKTU.css +0 -1
- package/dist/assets/loader-circle-MBgNSVIH.js +0 -1
- package/dist/assets/mcp-marketplace-page-CLmUstLN.js +0 -9
- package/dist/assets/mcp-marketplace-page-rZkmWPMy.js +0 -1
- package/dist/assets/model-config-page-Di0ySJD2.js +0 -1
- package/dist/assets/plus-vDqW5Kxp.js +0 -1
- package/dist/assets/providers-config-page-BAf2W0MV.js +0 -1
- package/dist/assets/remote-CLQ0IBM8.js +0 -1
- package/dist/assets/rotate-cw-CvNBv7_w.js +0 -1
- package/dist/assets/runtime-config-page-CflvvoDc.js +0 -1
- package/dist/assets/search-config-page-D0klFUXd.js +0 -1
- package/dist/assets/secrets-config-page-dVZ631Wp.js +0 -3
- package/dist/assets/security-config-C5gnlkuj.js +0 -1
- package/dist/assets/switch-CFLJFNSd.js +0 -1
- package/dist/assets/x-BF2KQ--V.js +0 -1
- /package/dist/assets/{config-hints-fGnUjDe9.js → config-hints-C_iP1zl_.js} +0 -0
|
@@ -2,34 +2,35 @@ import { cn } from "@/shared/lib/utils";
|
|
|
2
2
|
import { t } from "@/shared/lib/i18n";
|
|
3
3
|
import { THEME_OPTIONS, type UiTheme } from "@/shared/lib/theme";
|
|
4
4
|
import {
|
|
5
|
-
MessageCircle,
|
|
6
5
|
BookOpen,
|
|
7
|
-
BrainCircuit,
|
|
8
|
-
AlarmClock,
|
|
9
6
|
Languages,
|
|
10
7
|
Palette,
|
|
11
8
|
KeyRound,
|
|
12
9
|
Settings,
|
|
13
10
|
ArrowLeft,
|
|
14
|
-
Bot,
|
|
15
11
|
PanelLeftClose,
|
|
16
12
|
PanelLeftOpen,
|
|
17
|
-
type LucideIcon,
|
|
18
13
|
} from "lucide-react";
|
|
19
14
|
import { NavLink } from "react-router-dom";
|
|
20
15
|
import { useDocBrowser } from "@/shared/components/doc-browser";
|
|
21
16
|
import { BrandHeader } from "@/shared/components/common/brand-header";
|
|
22
17
|
import {
|
|
23
18
|
SidebarActionItem,
|
|
19
|
+
SidebarNavigationList,
|
|
24
20
|
SidebarNavLinkItem,
|
|
25
21
|
SidebarSelectItem,
|
|
22
|
+
type SidebarItemDensity,
|
|
23
|
+
type SidebarNavListItem,
|
|
26
24
|
} from "@/app/components/layout/sidebar-items";
|
|
27
25
|
import { useTheme } from "@/app/components/theme-provider";
|
|
28
26
|
import { SelectItem } from "@/shared/components/ui/select";
|
|
29
27
|
import { IconActionButton } from "@/shared/components/ui/actions/icon-action-button";
|
|
30
28
|
import { useAppPresenter } from "@/app/components/app-presenter-provider";
|
|
31
29
|
import { useRemoteStatus } from "@/features/remote";
|
|
32
|
-
import {
|
|
30
|
+
import {
|
|
31
|
+
getMainSidebarNavItems,
|
|
32
|
+
getSettingsNavSections,
|
|
33
|
+
} from "@/app/configs/app-navigation.config";
|
|
33
34
|
import { useLanguagePreference } from "@/features/settings";
|
|
34
35
|
import { viewportLayoutManager } from "@/app/managers/viewport-layout.manager";
|
|
35
36
|
import { useViewportLayoutStore } from "@/app/stores/viewport-layout.store";
|
|
@@ -50,12 +51,38 @@ type SidebarProps = {
|
|
|
50
51
|
mode: SidebarMode;
|
|
51
52
|
};
|
|
52
53
|
|
|
53
|
-
type
|
|
54
|
-
target: string;
|
|
54
|
+
type SidebarNavSection = {
|
|
55
55
|
label: string;
|
|
56
|
-
|
|
56
|
+
items: SidebarNavListItem[];
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
type SidebarNavigationModel = {
|
|
60
|
+
items: SidebarNavListItem[];
|
|
61
|
+
sections?: SidebarNavSection[];
|
|
62
|
+
density: SidebarItemDensity;
|
|
57
63
|
};
|
|
58
64
|
|
|
65
|
+
type SidebarTranslate = (key: string) => string;
|
|
66
|
+
|
|
67
|
+
function resolveSidebarNavigation(
|
|
68
|
+
isSettingsMode: boolean,
|
|
69
|
+
translate: SidebarTranslate,
|
|
70
|
+
): SidebarNavigationModel {
|
|
71
|
+
if (!isSettingsMode) {
|
|
72
|
+
return {
|
|
73
|
+
items: getMainSidebarNavItems(translate),
|
|
74
|
+
density: "default",
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const sections = getSettingsNavSections(translate);
|
|
79
|
+
return {
|
|
80
|
+
items: sections.flatMap((section) => section.items),
|
|
81
|
+
sections,
|
|
82
|
+
density: "compact",
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
59
86
|
function SidebarCollapseToggle({
|
|
60
87
|
isCollapsed,
|
|
61
88
|
onToggle,
|
|
@@ -106,7 +133,7 @@ function SettingsSidebarHeader({
|
|
|
106
133
|
to="/chat"
|
|
107
134
|
aria-label={t("backToMain")}
|
|
108
135
|
className={cn(
|
|
109
|
-
"group inline-flex min-w-0 items-center rounded-lg text-[12px] font-medium text-muted-foreground transition-colors hover:bg-gray-200/60 hover:text-gray-900 focus-visible:outline-none focus-visible:ring-
|
|
136
|
+
"group inline-flex min-w-0 items-center rounded-lg text-[12px] font-medium text-muted-foreground transition-colors hover:bg-gray-200/60 hover:text-gray-900 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border",
|
|
110
137
|
isCollapsed
|
|
111
138
|
? cn(
|
|
112
139
|
SIDEBAR_RAIL_CONTROL_CLASS,
|
|
@@ -197,13 +224,23 @@ function SidebarNavigation({
|
|
|
197
224
|
isSettingsMode,
|
|
198
225
|
isCollapsed,
|
|
199
226
|
items,
|
|
227
|
+
sections,
|
|
200
228
|
density,
|
|
201
229
|
}: {
|
|
202
230
|
isSettingsMode: boolean;
|
|
203
231
|
isCollapsed: boolean;
|
|
204
|
-
items:
|
|
205
|
-
|
|
232
|
+
items: SidebarNavListItem[];
|
|
233
|
+
sections?: SidebarNavSection[];
|
|
234
|
+
density: SidebarItemDensity;
|
|
206
235
|
}) {
|
|
236
|
+
const listClassName = cn(
|
|
237
|
+
isCollapsed
|
|
238
|
+
? cn(SIDEBAR_RAIL_STACK_CLASS, "pb-3")
|
|
239
|
+
: isSettingsMode
|
|
240
|
+
? "space-y-0.5 pb-3"
|
|
241
|
+
: "space-y-1 pb-4",
|
|
242
|
+
);
|
|
243
|
+
|
|
207
244
|
return (
|
|
208
245
|
<nav
|
|
209
246
|
className={cn(
|
|
@@ -212,30 +249,34 @@ function SidebarNavigation({
|
|
|
212
249
|
SIDEBAR_SCROLL_EDGE_FADE_CLASS,
|
|
213
250
|
)}
|
|
214
251
|
>
|
|
215
|
-
|
|
216
|
-
className=
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
252
|
+
{sections && !isCollapsed ? (
|
|
253
|
+
<div className="space-y-3 pb-3">
|
|
254
|
+
{sections.map((section) => (
|
|
255
|
+
<section
|
|
256
|
+
key={section.label}
|
|
257
|
+
aria-label={section.label}
|
|
258
|
+
className="space-y-1"
|
|
259
|
+
>
|
|
260
|
+
<h2 className="px-3 text-[11px] font-semibold text-muted-foreground/70">
|
|
261
|
+
{section.label}
|
|
262
|
+
</h2>
|
|
263
|
+
<SidebarNavigationList
|
|
264
|
+
isCollapsed={isCollapsed}
|
|
265
|
+
items={section.items}
|
|
266
|
+
density={density}
|
|
267
|
+
className="space-y-0.5"
|
|
268
|
+
/>
|
|
269
|
+
</section>
|
|
270
|
+
))}
|
|
271
|
+
</div>
|
|
272
|
+
) : (
|
|
273
|
+
<SidebarNavigationList
|
|
274
|
+
isCollapsed={isCollapsed}
|
|
275
|
+
items={items}
|
|
276
|
+
density={density}
|
|
277
|
+
className={listClassName}
|
|
278
|
+
/>
|
|
279
|
+
)}
|
|
239
280
|
</nav>
|
|
240
281
|
);
|
|
241
282
|
}
|
|
@@ -258,7 +299,7 @@ export function Sidebar({ mode }: SidebarProps) {
|
|
|
258
299
|
const isSettingsMode = mode === "settings";
|
|
259
300
|
const currentThemeLabel = t(
|
|
260
301
|
THEME_OPTIONS.find((option) => option.value === theme)?.labelKey ??
|
|
261
|
-
"
|
|
302
|
+
"themeWork",
|
|
262
303
|
);
|
|
263
304
|
const accountEmail = remoteStatus.data?.account.email?.trim();
|
|
264
305
|
const accountConnected = Boolean(remoteStatus.data?.account.loggedIn);
|
|
@@ -267,31 +308,11 @@ export function Sidebar({ mode }: SidebarProps) {
|
|
|
267
308
|
if (theme !== nextTheme) setTheme(nextTheme);
|
|
268
309
|
};
|
|
269
310
|
|
|
270
|
-
const
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
},
|
|
276
|
-
{
|
|
277
|
-
target: "/chat/cron",
|
|
278
|
-
label: t("cron"),
|
|
279
|
-
icon: AlarmClock,
|
|
280
|
-
},
|
|
281
|
-
{
|
|
282
|
-
target: "/chat/skills",
|
|
283
|
-
label: t("marketplaceFilterSkills"),
|
|
284
|
-
icon: BrainCircuit,
|
|
285
|
-
},
|
|
286
|
-
{
|
|
287
|
-
target: "/agents",
|
|
288
|
-
label: t("agentsPageTitle"),
|
|
289
|
-
icon: Bot,
|
|
290
|
-
},
|
|
291
|
-
];
|
|
292
|
-
|
|
293
|
-
const navItems = isSettingsMode ? getSettingsNavItems(t) : mainNavItems;
|
|
294
|
-
const sidebarDensity = isSettingsMode ? "compact" : "default";
|
|
311
|
+
const {
|
|
312
|
+
items: navItems,
|
|
313
|
+
sections: settingsNavSections,
|
|
314
|
+
density: sidebarDensity,
|
|
315
|
+
} = resolveSidebarNavigation(isSettingsMode, t);
|
|
295
316
|
|
|
296
317
|
return (
|
|
297
318
|
<aside
|
|
@@ -314,6 +335,7 @@ export function Sidebar({ mode }: SidebarProps) {
|
|
|
314
335
|
isSettingsMode={isSettingsMode}
|
|
315
336
|
isCollapsed={isCollapsed}
|
|
316
337
|
items={navItems}
|
|
338
|
+
sections={settingsNavSections}
|
|
317
339
|
density={sidebarDensity}
|
|
318
340
|
/>
|
|
319
341
|
|
|
@@ -2,6 +2,7 @@ import type { LucideIcon } from "lucide-react";
|
|
|
2
2
|
import {
|
|
3
3
|
Bot,
|
|
4
4
|
BrainCircuit,
|
|
5
|
+
AlarmClock,
|
|
5
6
|
Cpu,
|
|
6
7
|
Download,
|
|
7
8
|
KeyRound,
|
|
@@ -25,6 +26,11 @@ export type AppNavigationItem = {
|
|
|
25
26
|
icon: LucideIcon;
|
|
26
27
|
};
|
|
27
28
|
|
|
29
|
+
export type AppNavigationSection = {
|
|
30
|
+
label: string;
|
|
31
|
+
items: AppNavigationItem[];
|
|
32
|
+
};
|
|
33
|
+
|
|
28
34
|
function matchesRouteTarget(pathname: string, target: string): boolean {
|
|
29
35
|
const normalizedPath = pathname.toLowerCase();
|
|
30
36
|
const normalizedTarget = target.toLowerCase();
|
|
@@ -80,6 +86,33 @@ export function getMobileBottomNavItems(
|
|
|
80
86
|
];
|
|
81
87
|
}
|
|
82
88
|
|
|
89
|
+
export function getMainSidebarNavItems(
|
|
90
|
+
translate: Translate,
|
|
91
|
+
): AppNavigationItem[] {
|
|
92
|
+
return [
|
|
93
|
+
{
|
|
94
|
+
target: "/chat",
|
|
95
|
+
label: translate("chat"),
|
|
96
|
+
icon: MessageCircle,
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
target: "/chat/cron",
|
|
100
|
+
label: translate("cron"),
|
|
101
|
+
icon: AlarmClock,
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
target: "/chat/skills",
|
|
105
|
+
label: translate("marketplaceFilterSkills"),
|
|
106
|
+
icon: BrainCircuit,
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
target: "/agents",
|
|
110
|
+
label: translate("agentsPageTitle"),
|
|
111
|
+
icon: Bot,
|
|
112
|
+
},
|
|
113
|
+
];
|
|
114
|
+
}
|
|
115
|
+
|
|
83
116
|
export function getSettingsNavItems(
|
|
84
117
|
translate: Translate,
|
|
85
118
|
): AppNavigationItem[] {
|
|
@@ -142,6 +175,22 @@ export function getSettingsNavItems(
|
|
|
142
175
|
];
|
|
143
176
|
}
|
|
144
177
|
|
|
178
|
+
export function getSettingsNavSections(
|
|
179
|
+
translate: Translate,
|
|
180
|
+
): AppNavigationSection[] {
|
|
181
|
+
const items = getSettingsNavItems(translate);
|
|
182
|
+
return [
|
|
183
|
+
{
|
|
184
|
+
label: translate("settingsGroupBasic"),
|
|
185
|
+
items: items.slice(0, 3),
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
label: translate("settingsGroupAdvanced"),
|
|
189
|
+
items: items.slice(3),
|
|
190
|
+
},
|
|
191
|
+
];
|
|
192
|
+
}
|
|
193
|
+
|
|
145
194
|
export function getMobileSettingsNavItems(
|
|
146
195
|
translate: Translate,
|
|
147
196
|
): AppNavigationItem[] {
|
|
@@ -284,6 +284,101 @@
|
|
|
284
284
|
}
|
|
285
285
|
}
|
|
286
286
|
|
|
287
|
+
@layer base {
|
|
288
|
+
:root[data-theme="work"] {
|
|
289
|
+
/* ========================================
|
|
290
|
+
BRAND COLORS (Work White Ink)
|
|
291
|
+
======================================== */
|
|
292
|
+
--brand-50: 0 0% 97%;
|
|
293
|
+
--brand-100: 0 0% 94%;
|
|
294
|
+
--brand-200: 0 0% 88%;
|
|
295
|
+
--brand-300: 0 0% 78%;
|
|
296
|
+
--brand-400: 0 0% 58%;
|
|
297
|
+
--brand-500: 0 0% 23%;
|
|
298
|
+
--brand-600: 0 0% 18%;
|
|
299
|
+
--brand-700: 0 0% 12%;
|
|
300
|
+
--brand-800: 0 0% 7%;
|
|
301
|
+
--brand-900: 0 0% 4%;
|
|
302
|
+
|
|
303
|
+
/* ========================================
|
|
304
|
+
NEUTRAL COLORS (White Canvas / Soft Gray Rail)
|
|
305
|
+
======================================== */
|
|
306
|
+
--gray-50: 0 0% 100%;
|
|
307
|
+
--gray-100: 0 0% 95%;
|
|
308
|
+
--gray-200: 0 0% 90%;
|
|
309
|
+
--gray-300: 0 0% 84%;
|
|
310
|
+
--gray-400: 0 0% 70%;
|
|
311
|
+
--gray-500: 0 0% 46%;
|
|
312
|
+
--gray-600: 0 0% 34%;
|
|
313
|
+
--gray-700: 0 0% 28%;
|
|
314
|
+
--gray-800: 0 0% 13%;
|
|
315
|
+
--gray-900: 0 0% 7%;
|
|
316
|
+
|
|
317
|
+
/* Semantic Colors */
|
|
318
|
+
--background: var(--gray-50);
|
|
319
|
+
--background-secondary: var(--gray-100);
|
|
320
|
+
--background-tertiary: var(--gray-200);
|
|
321
|
+
--foreground: var(--gray-800);
|
|
322
|
+
--foreground-secondary: var(--gray-700);
|
|
323
|
+
--foreground-tertiary: var(--gray-500);
|
|
324
|
+
--foreground-muted: var(--gray-400);
|
|
325
|
+
--primary: var(--brand-500);
|
|
326
|
+
--primary-hover: var(--brand-600);
|
|
327
|
+
--primary-active: var(--brand-700);
|
|
328
|
+
--primary-foreground: 0 0% 100%;
|
|
329
|
+
--secondary: var(--gray-100);
|
|
330
|
+
--secondary-hover: var(--gray-200);
|
|
331
|
+
--secondary-foreground: var(--gray-800);
|
|
332
|
+
--accent: var(--gray-200);
|
|
333
|
+
--accent-foreground: var(--gray-800);
|
|
334
|
+
--muted: var(--gray-100);
|
|
335
|
+
--muted-foreground: var(--gray-500);
|
|
336
|
+
--card: 0 0% 100%;
|
|
337
|
+
--card-foreground: var(--gray-800);
|
|
338
|
+
--card-border: var(--gray-200);
|
|
339
|
+
--popover: 0 0% 100%;
|
|
340
|
+
--popover-foreground: var(--gray-800);
|
|
341
|
+
--border: var(--gray-200);
|
|
342
|
+
--border-hover: var(--gray-300);
|
|
343
|
+
--border-active: var(--gray-600);
|
|
344
|
+
--input: 0 0% 100%;
|
|
345
|
+
--input-border: var(--gray-200);
|
|
346
|
+
--input-focus: var(--gray-600);
|
|
347
|
+
--ring: var(--gray-600);
|
|
348
|
+
--ring-offset: var(--gray-50);
|
|
349
|
+
|
|
350
|
+
/* Shadows (bright neutral tint) */
|
|
351
|
+
--shadow-xs: 0 1px 2px 0 rgb(20 24 28 / 0.03);
|
|
352
|
+
--shadow-sm: 0 1px 3px 0 rgb(20 24 28 / 0.05), 0 1px 2px -1px rgb(20 24 28 / 0.04);
|
|
353
|
+
--shadow-md: 0 4px 6px -1px rgb(20 24 28 / 0.05), 0 2px 4px -2px rgb(20 24 28 / 0.04);
|
|
354
|
+
--shadow-lg: 0 10px 15px -3px rgb(20 24 28 / 0.06), 0 4px 6px -4px rgb(20 24 28 / 0.04);
|
|
355
|
+
--shadow-xl: 0 20px 25px -5px rgb(20 24 28 / 0.08), 0 8px 10px -6px rgb(20 24 28 / 0.04);
|
|
356
|
+
--shadow-2xl: 0 25px 50px -12px rgb(20 24 28 / 0.14);
|
|
357
|
+
--shadow-card: 0 0 8px 0 rgba(20, 24, 28, 0.04);
|
|
358
|
+
--shadow-card-hover: 0 0 16px 0 rgba(20, 24, 28, 0.06);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
:root[data-theme="work"] .nextclaw-chat-message-user {
|
|
362
|
+
background-color: hsl(var(--gray-100));
|
|
363
|
+
border-color: transparent;
|
|
364
|
+
color: hsl(var(--gray-800));
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/* User bubble is light in work theme; keep clickable skill tokens as link-colored text. */
|
|
368
|
+
:root[data-theme="work"] .nextclaw-chat-message-user .nextclaw-chat-inline-token {
|
|
369
|
+
border-color: transparent;
|
|
370
|
+
background-color: transparent;
|
|
371
|
+
color: var(--md-link, #1f73c9);
|
|
372
|
+
box-shadow: none;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
:root[data-theme="work"] .nextclaw-chat-message-user .nextclaw-chat-inline-token > span:first-child {
|
|
376
|
+
color: currentColor;
|
|
377
|
+
opacity: 0.8;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
}
|
|
381
|
+
|
|
287
382
|
@layer base {
|
|
288
383
|
:root[data-theme="warm"] {
|
|
289
384
|
/* ========================================
|
|
@@ -812,10 +907,10 @@
|
|
|
812
907
|
-webkit-backdrop-filter: blur(12px);
|
|
813
908
|
}
|
|
814
909
|
|
|
815
|
-
/* Focus Ring */
|
|
910
|
+
/* Focus Ring — light inset-style ring, no offset box */
|
|
816
911
|
.focus-ring {
|
|
817
|
-
@apply focus:outline-none focus-visible:ring-
|
|
818
|
-
--tw-ring-color: hsl(var(--
|
|
819
|
-
--tw-ring-offset-color:
|
|
912
|
+
@apply focus:outline-none focus-visible:ring-1 focus-visible:ring-offset-0;
|
|
913
|
+
--tw-ring-color: hsl(var(--border));
|
|
914
|
+
--tw-ring-offset-color: transparent;
|
|
820
915
|
}
|
|
821
916
|
}
|
|
@@ -5,6 +5,7 @@ import { BookOpen, ChevronDown } from 'lucide-react';
|
|
|
5
5
|
import { toast } from 'sonner';
|
|
6
6
|
import { LogoBadge } from '@/shared/components/common/logo-badge';
|
|
7
7
|
import { Button } from '@/shared/components/ui/button';
|
|
8
|
+
import { FormActions } from '@/shared/components/ui/actions/form-actions';
|
|
8
9
|
import { StatusDot } from '@/shared/components/status/status-dot';
|
|
9
10
|
import { nextclawClient } from '@/shared/lib/api';
|
|
10
11
|
import { useConfig, useConfigMeta, useConfigSchema, useExecuteConfigAction, useUpdateChannel } from '@/shared/hooks/use-config';
|
|
@@ -363,17 +364,19 @@ function ChannelFormEditor({
|
|
|
363
364
|
/>
|
|
364
365
|
</ConfigSplitPaneBody>
|
|
365
366
|
|
|
366
|
-
<ConfigSplitPaneFooter
|
|
367
|
-
<
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
{
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
367
|
+
<ConfigSplitPaneFooter>
|
|
368
|
+
<FormActions align="between">
|
|
369
|
+
<div className="flex flex-wrap items-center gap-2">
|
|
370
|
+
{actions.filter((action) => action.trigger === 'manual').map((action) => (
|
|
371
|
+
<Button key={action.id} type="button" size="sm" onClick={() => void handleManualAction(action)} disabled={disabled} variant="secondary">
|
|
372
|
+
{runningActionId === action.id ? t('connecting') : action.title}
|
|
373
|
+
</Button>
|
|
374
|
+
))}
|
|
375
|
+
</div>
|
|
376
|
+
<Button type="submit" size="sm" disabled={disabled}>
|
|
377
|
+
{updateChannel.isPending ? t('saving') : t('save')}
|
|
378
|
+
</Button>
|
|
379
|
+
</FormActions>
|
|
377
380
|
</ConfigSplitPaneFooter>
|
|
378
381
|
</form>
|
|
379
382
|
</ConfigSplitDetailPane>
|
|
@@ -224,6 +224,46 @@ describe("ChatConversationHeaderSection", () => {
|
|
|
224
224
|
|
|
225
225
|
expect(screen.queryByRole("button", { name: /Switch session/ })).toBeNull();
|
|
226
226
|
expect(screen.getByText("Parent Task")).toBeTruthy();
|
|
227
|
+
expect(screen.queryByText("Native")).toBeNull();
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
it("keeps the runtime badge for a non-native session", () => {
|
|
231
|
+
useChatQueryStore.setState({
|
|
232
|
+
snapshot: {
|
|
233
|
+
...useChatQueryStore.getState().snapshot,
|
|
234
|
+
sessionsQuery: {
|
|
235
|
+
data: {
|
|
236
|
+
sessions: [
|
|
237
|
+
createSummary({
|
|
238
|
+
sessionId: "parent-session-1",
|
|
239
|
+
metadata: {
|
|
240
|
+
label: "Parent Task",
|
|
241
|
+
session_type: "codex",
|
|
242
|
+
},
|
|
243
|
+
}),
|
|
244
|
+
],
|
|
245
|
+
total: 1,
|
|
246
|
+
},
|
|
247
|
+
} as never,
|
|
248
|
+
sessionTypesQuery: {
|
|
249
|
+
data: {
|
|
250
|
+
defaultType: "native",
|
|
251
|
+
options: [{ value: "codex", label: "Codex", ready: true }],
|
|
252
|
+
},
|
|
253
|
+
} as never,
|
|
254
|
+
},
|
|
255
|
+
});
|
|
256
|
+
mocks.sessionItems = [
|
|
257
|
+
createSessionListItem({
|
|
258
|
+
key: "parent-session-1",
|
|
259
|
+
label: "Parent Task",
|
|
260
|
+
sessionType: "codex",
|
|
261
|
+
}),
|
|
262
|
+
];
|
|
263
|
+
|
|
264
|
+
renderHeaderSection();
|
|
265
|
+
|
|
266
|
+
expect(screen.getByText("Codex")).toBeTruthy();
|
|
227
267
|
});
|
|
228
268
|
|
|
229
269
|
it("keeps session switching available from a collapsed new-session header", async () => {
|
|
@@ -53,6 +53,8 @@ export function ChatConversationHeaderSection({
|
|
|
53
53
|
sessionTypeOptions.find((option) => option.value === sessionType) ?? null;
|
|
54
54
|
const sessionTypeLabel =
|
|
55
55
|
sessionTypeOption?.label ?? resolveSessionTypeLabel(sessionType);
|
|
56
|
+
const shouldShowSessionTypeBadge =
|
|
57
|
+
sessionType !== DEFAULT_SESSION_TYPE && Boolean(sessionTypeLabel);
|
|
56
58
|
const sessionProjectRoot = selectedSession?.projectRoot ?? null;
|
|
57
59
|
const sessionProjectName =
|
|
58
60
|
selectedSession?.projectName ?? getSessionProjectName(sessionProjectRoot);
|
|
@@ -110,7 +112,7 @@ export function ChatConversationHeaderSection({
|
|
|
110
112
|
) : null
|
|
111
113
|
}
|
|
112
114
|
sessionTypeBadge={
|
|
113
|
-
|
|
115
|
+
shouldShowSessionTypeBadge ? (
|
|
114
116
|
<span className="inline-flex shrink-0 items-center gap-1.5 rounded-full border border-border bg-muted px-2 py-0.5 text-[11px] font-medium text-muted-foreground">
|
|
115
117
|
{sessionTypeOption?.icon?.src ? (
|
|
116
118
|
<span className="inline-flex h-[1.125rem] w-[1.125rem] items-center justify-center">
|
|
@@ -34,7 +34,7 @@ export function ChatConversationPanel({
|
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
return (
|
|
37
|
-
<section className="flex-1 min-h-0 flex overflow-hidden bg-background">
|
|
37
|
+
<section className="relative flex-1 min-h-0 flex overflow-hidden bg-background">
|
|
38
38
|
<div className="flex min-h-0 flex-1 flex-col overflow-hidden">
|
|
39
39
|
<ChatConversationParentBanner />
|
|
40
40
|
<ChatConversationHeaderSection
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { render, screen } from "@testing-library/react";
|
|
2
|
+
import { describe, expect, it, vi } from "vitest";
|
|
3
|
+
import {
|
|
4
|
+
ChatSidebarDesktopToolbar,
|
|
5
|
+
ChatSidebarMobileToolbar,
|
|
6
|
+
} from "@/features/chat/components/layout/chat-sidebar-toolbar";
|
|
7
|
+
import type { ChatSessionTypeOption } from "@/features/chat/features/session-type/utils/chat-session-type.utils";
|
|
8
|
+
|
|
9
|
+
const sessionTypeOptions: ChatSessionTypeOption[] = [
|
|
10
|
+
{ value: "native", label: "Native", icon: null, ready: true },
|
|
11
|
+
{ value: "codex", label: "Codex", icon: null, ready: true },
|
|
12
|
+
];
|
|
13
|
+
|
|
14
|
+
const toolbarProps = {
|
|
15
|
+
query: "",
|
|
16
|
+
defaultSessionType: "native",
|
|
17
|
+
sessionTypeOptions,
|
|
18
|
+
nonDefaultSessionTypeOptions: [sessionTypeOptions[1]],
|
|
19
|
+
selectedNewSessionType: "native",
|
|
20
|
+
selectedNewSessionTypeOption: sessionTypeOptions[0],
|
|
21
|
+
isCreateMenuOpen: false,
|
|
22
|
+
onCreateMenuOpenChange: vi.fn(),
|
|
23
|
+
onCreateSession: vi.fn(),
|
|
24
|
+
onSelectNewSessionType: vi.fn(),
|
|
25
|
+
onQueryChange: vi.fn(),
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
function searchIconClassName() {
|
|
29
|
+
return (
|
|
30
|
+
screen
|
|
31
|
+
.getByPlaceholderText("Search conversations...")
|
|
32
|
+
.previousElementSibling?.getAttribute("class") ?? ""
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
describe("ChatSidebarToolbar", () => {
|
|
37
|
+
it("keeps desktop search icon transparent to pointer input", () => {
|
|
38
|
+
render(<ChatSidebarDesktopToolbar {...toolbarProps} />);
|
|
39
|
+
|
|
40
|
+
expect(searchIconClassName()).toContain("pointer-events-none");
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it("keeps mobile search icon transparent to pointer input", () => {
|
|
44
|
+
render(<ChatSidebarMobileToolbar {...toolbarProps} />);
|
|
45
|
+
|
|
46
|
+
expect(searchIconClassName()).toContain("pointer-events-none");
|
|
47
|
+
});
|
|
48
|
+
});
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { fireEvent, render, screen } from "@testing-library/react";
|
|
2
|
+
import { MemoryRouter } from "react-router-dom";
|
|
3
|
+
import { describe, expect, it, vi } from "vitest";
|
|
4
|
+
import { ChatSidebarUtilityMenu } from "@/features/chat/components/layout/chat-sidebar-utility-menu";
|
|
5
|
+
|
|
6
|
+
function renderUtilityMenu() {
|
|
7
|
+
return render(
|
|
8
|
+
<MemoryRouter>
|
|
9
|
+
<ChatSidebarUtilityMenu
|
|
10
|
+
isOpen
|
|
11
|
+
onOpenChange={vi.fn()}
|
|
12
|
+
currentTheme="warm"
|
|
13
|
+
currentThemeLabel="Warm"
|
|
14
|
+
themeOptions={[{ value: "warm", label: "Warm" }]}
|
|
15
|
+
onSelectTheme={vi.fn()}
|
|
16
|
+
currentLanguage="en"
|
|
17
|
+
currentLanguageLabel="English"
|
|
18
|
+
languageOptions={[{ value: "en", label: "English" }]}
|
|
19
|
+
onSelectLanguage={vi.fn()}
|
|
20
|
+
onOpenDocs={vi.fn()}
|
|
21
|
+
onOpenApps={vi.fn()}
|
|
22
|
+
/>
|
|
23
|
+
</MemoryRouter>,
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function appendComposerFocusTarget(): HTMLElement {
|
|
28
|
+
const composerShell = document.createElement("div");
|
|
29
|
+
composerShell.className = "nextclaw-chat-input-bar-shell";
|
|
30
|
+
const composer = document.createElement("div");
|
|
31
|
+
composer.setAttribute("contenteditable", "true");
|
|
32
|
+
composer.setAttribute("role", "textbox");
|
|
33
|
+
composer.tabIndex = 0;
|
|
34
|
+
composerShell.appendChild(composer);
|
|
35
|
+
document.body.appendChild(composerShell);
|
|
36
|
+
return composer;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
describe("ChatSidebarUtilityMenu", () => {
|
|
40
|
+
it("stays open when the streaming composer restores focus", () => {
|
|
41
|
+
const composer = appendComposerFocusTarget();
|
|
42
|
+
|
|
43
|
+
try {
|
|
44
|
+
renderUtilityMenu();
|
|
45
|
+
|
|
46
|
+
expect(screen.getByRole("button", { name: "Help Docs" })).toBeTruthy();
|
|
47
|
+
|
|
48
|
+
fireEvent.focusIn(composer);
|
|
49
|
+
|
|
50
|
+
expect(screen.getByRole("button", { name: "Help Docs" })).toBeTruthy();
|
|
51
|
+
} finally {
|
|
52
|
+
composer.closest(".nextclaw-chat-input-bar-shell")?.remove();
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
});
|
|
@@ -134,7 +134,6 @@ export function ChatSidebarSessionArea({
|
|
|
134
134
|
isCollapsed,
|
|
135
135
|
isLoading,
|
|
136
136
|
isProjectFirstView,
|
|
137
|
-
onCreateSession,
|
|
138
137
|
onSelectMode,
|
|
139
138
|
projectGroups,
|
|
140
139
|
renderSessionItem,
|
|
@@ -145,7 +144,6 @@ export function ChatSidebarSessionArea({
|
|
|
145
144
|
isCollapsed: boolean;
|
|
146
145
|
isLoading: boolean;
|
|
147
146
|
isProjectFirstView: boolean;
|
|
148
|
-
onCreateSession: (sessionType: string, projectRoot?: string | null) => void;
|
|
149
147
|
onSelectMode: (mode: "time-first" | "project-first") => void;
|
|
150
148
|
projectGroups: ReturnType<typeof groupSessionsByProject>;
|
|
151
149
|
renderSessionItem: (item: NcpSessionListItemView) => JSX.Element;
|
|
@@ -183,7 +181,6 @@ export function ChatSidebarSessionArea({
|
|
|
183
181
|
defaultSessionType={defaultSessionType}
|
|
184
182
|
sessionTypeOptions={sessionTypeOptions}
|
|
185
183
|
renderSessionItem={renderSessionItem}
|
|
186
|
-
onCreateSession={onCreateSession}
|
|
187
184
|
/>
|
|
188
185
|
</div>
|
|
189
186
|
</>
|