mirror of
https://github.com/HKUDS/nanobot.git
synced 2026-09-03 17:52:00 +03:00
fix(webui): align native sidebar controls
This commit is contained in:
+7
-131
@@ -8,7 +8,7 @@ import {
|
|||||||
useState,
|
useState,
|
||||||
type ReactNode,
|
type ReactNode,
|
||||||
} from "react";
|
} from "react";
|
||||||
import { Eye, EyeOff, Moon, PanelLeft, ShieldCheck, Sun, X } from "lucide-react";
|
import { Eye, EyeOff, Moon, ShieldCheck, Sun, X } from "lucide-react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { channelUiPresentation } from "@/channel-plugins/registry";
|
import { channelUiPresentation } from "@/channel-plugins/registry";
|
||||||
import { Sidebar } from "@/components/Sidebar";
|
import { Sidebar } from "@/components/Sidebar";
|
||||||
@@ -475,39 +475,12 @@ function isBootstrapAuthRequired(error: unknown): boolean {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function HostChrome({
|
function HostChrome({
|
||||||
onToggleSidebar,
|
|
||||||
onSidebarPreviewEnter,
|
|
||||||
onSidebarPreviewLeave,
|
|
||||||
sidebarOpen = true,
|
|
||||||
rightAction,
|
rightAction,
|
||||||
}: {
|
}: {
|
||||||
onToggleSidebar?: () => void;
|
|
||||||
onSidebarPreviewEnter?: () => void;
|
|
||||||
onSidebarPreviewLeave?: () => void;
|
|
||||||
sidebarOpen?: boolean;
|
|
||||||
rightAction?: ReactNode;
|
rightAction?: ReactNode;
|
||||||
}) {
|
}) {
|
||||||
const { t } = useTranslation();
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<header className="host-drag-region pointer-events-none absolute inset-x-0 top-0 z-40 h-11 bg-transparent text-foreground/90">
|
<header className="host-drag-region pointer-events-none absolute inset-x-0 top-0 z-40 h-11 bg-transparent text-foreground/90">
|
||||||
{onToggleSidebar ? (
|
|
||||||
<Button
|
|
||||||
type="button"
|
|
||||||
variant="ghost"
|
|
||||||
size="icon"
|
|
||||||
aria-label={t("thread.header.toggleSidebar")}
|
|
||||||
data-testid="host-sidebar-toggle"
|
|
||||||
onClick={onToggleSidebar}
|
|
||||||
onFocus={!sidebarOpen ? onSidebarPreviewEnter : undefined}
|
|
||||||
onBlur={!sidebarOpen ? onSidebarPreviewLeave : undefined}
|
|
||||||
onMouseEnter={!sidebarOpen ? onSidebarPreviewEnter : undefined}
|
|
||||||
onMouseLeave={!sidebarOpen ? onSidebarPreviewLeave : undefined}
|
|
||||||
className="host-no-drag pointer-events-auto absolute left-[88px] top-[8px] h-7 w-7 rounded-lg bg-transparent text-muted-foreground/85 shadow-none hover:bg-transparent hover:text-foreground"
|
|
||||||
>
|
|
||||||
<PanelLeft className="h-[15px] w-[15px]" strokeWidth={1.75} />
|
|
||||||
</Button>
|
|
||||||
) : null}
|
|
||||||
{rightAction ? (
|
{rightAction ? (
|
||||||
<div className="host-no-drag pointer-events-auto absolute right-3 top-2">
|
<div className="host-no-drag pointer-events-auto absolute right-3 top-2">
|
||||||
{rightAction}
|
{rightAction}
|
||||||
@@ -1055,7 +1028,6 @@ function Shell({
|
|||||||
useState<SettingsSectionKey>(initialRouteRef.current.settingsSection);
|
useState<SettingsSectionKey>(initialRouteRef.current.settingsSection);
|
||||||
const [hostSidebarOpen, setHostSidebarOpen] =
|
const [hostSidebarOpen, setHostSidebarOpen] =
|
||||||
useState<boolean>(readSidebarOpen);
|
useState<boolean>(readSidebarOpen);
|
||||||
const [hostSidebarPreviewOpen, setHostSidebarPreviewOpen] = useState(false);
|
|
||||||
const [mobileSidebarOpen, setMobileSidebarOpen] = useState(false);
|
const [mobileSidebarOpen, setMobileSidebarOpen] = useState(false);
|
||||||
const [sessionSearchOpen, setSessionSearchOpen] = useState(false);
|
const [sessionSearchOpen, setSessionSearchOpen] = useState(false);
|
||||||
const mobileWorkbench = useMediaQuery("(max-width: 767px)");
|
const mobileWorkbench = useMediaQuery("(max-width: 767px)");
|
||||||
@@ -1112,7 +1084,6 @@ function Shell({
|
|||||||
const activeChatIdRef = useRef<string | null>(null);
|
const activeChatIdRef = useRef<string | null>(null);
|
||||||
const pendingCreatedSessionKeyRef = useRef<string | null>(null);
|
const pendingCreatedSessionKeyRef = useRef<string | null>(null);
|
||||||
const temporarySessionsRef = useRef<Record<string, ChatSummary>>({});
|
const temporarySessionsRef = useRef<Record<string, ChatSummary>>({});
|
||||||
const hostSidebarPreviewCloseTimerRef = useRef<number | null>(null);
|
|
||||||
const effectiveRuntimeSurface =
|
const effectiveRuntimeSurface =
|
||||||
settingsSnapshot?.surface ?? settingsSnapshot?.runtime_surface ?? runtimeSurface;
|
settingsSnapshot?.surface ?? settingsSnapshot?.runtime_surface ?? runtimeSurface;
|
||||||
const showHostChrome = effectiveRuntimeSurface === "native";
|
const showHostChrome = effectiveRuntimeSurface === "native";
|
||||||
@@ -1453,74 +1424,13 @@ function Shell({
|
|||||||
});
|
});
|
||||||
}, [client, loading, sessions]);
|
}, [client, loading, sessions]);
|
||||||
|
|
||||||
const clearHostSidebarPreviewCloseTimer = useCallback(() => {
|
const closeHostSidebar = useCallback(() => {
|
||||||
if (hostSidebarPreviewCloseTimerRef.current === null) return;
|
setHostSidebarOpen(false);
|
||||||
window.clearTimeout(hostSidebarPreviewCloseTimerRef.current);
|
|
||||||
hostSidebarPreviewCloseTimerRef.current = null;
|
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const closeHostSidebarPreview = useCallback(() => {
|
|
||||||
clearHostSidebarPreviewCloseTimer();
|
|
||||||
setHostSidebarPreviewOpen(false);
|
|
||||||
}, [clearHostSidebarPreviewCloseTimer]);
|
|
||||||
|
|
||||||
const openHostSidebarPreview = useCallback(() => {
|
|
||||||
if (!showHostChrome || !showMainSidebar || hostSidebarOpen) return;
|
|
||||||
clearHostSidebarPreviewCloseTimer();
|
|
||||||
setHostSidebarPreviewOpen(true);
|
|
||||||
}, [
|
|
||||||
clearHostSidebarPreviewCloseTimer,
|
|
||||||
hostSidebarOpen,
|
|
||||||
showHostChrome,
|
|
||||||
showMainSidebar,
|
|
||||||
]);
|
|
||||||
|
|
||||||
const scheduleHostSidebarPreviewClose = useCallback(() => {
|
|
||||||
clearHostSidebarPreviewCloseTimer();
|
|
||||||
if (!showHostChrome || !showMainSidebar || hostSidebarOpen) {
|
|
||||||
setHostSidebarPreviewOpen(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
hostSidebarPreviewCloseTimerRef.current = window.setTimeout(() => {
|
|
||||||
setHostSidebarPreviewOpen(false);
|
|
||||||
hostSidebarPreviewCloseTimerRef.current = null;
|
|
||||||
}, 160);
|
|
||||||
}, [
|
|
||||||
clearHostSidebarPreviewCloseTimer,
|
|
||||||
hostSidebarOpen,
|
|
||||||
showHostChrome,
|
|
||||||
showMainSidebar,
|
|
||||||
]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
return () => clearHostSidebarPreviewCloseTimer();
|
|
||||||
}, [clearHostSidebarPreviewCloseTimer]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!showHostChrome || !showMainSidebar || hostSidebarOpen) {
|
|
||||||
closeHostSidebarPreview();
|
|
||||||
}
|
|
||||||
}, [
|
|
||||||
closeHostSidebarPreview,
|
|
||||||
hostSidebarOpen,
|
|
||||||
showHostChrome,
|
|
||||||
showMainSidebar,
|
|
||||||
]);
|
|
||||||
|
|
||||||
const closeHostSidebar = useCallback(() => {
|
|
||||||
closeHostSidebarPreview();
|
|
||||||
setHostSidebarOpen(false);
|
|
||||||
}, [closeHostSidebarPreview]);
|
|
||||||
|
|
||||||
const openHostSidebar = useCallback(() => {
|
const openHostSidebar = useCallback(() => {
|
||||||
closeHostSidebarPreview();
|
|
||||||
setHostSidebarOpen(true);
|
setHostSidebarOpen(true);
|
||||||
}, [closeHostSidebarPreview]);
|
}, []);
|
||||||
|
|
||||||
const toggleHostSidebar = useCallback(() => {
|
|
||||||
closeHostSidebarPreview();
|
|
||||||
setHostSidebarOpen((v) => !v);
|
|
||||||
}, [closeHostSidebarPreview]);
|
|
||||||
|
|
||||||
const closeMobileSidebar = useCallback(() => {
|
const closeMobileSidebar = useCallback(() => {
|
||||||
setMobileSidebarOpen(false);
|
setMobileSidebarOpen(false);
|
||||||
@@ -1531,12 +1441,11 @@ function Shell({
|
|||||||
typeof window !== "undefined" &&
|
typeof window !== "undefined" &&
|
||||||
window.matchMedia("(min-width: 1024px)").matches;
|
window.matchMedia("(min-width: 1024px)").matches;
|
||||||
if (isNativeHost) {
|
if (isNativeHost) {
|
||||||
closeHostSidebarPreview();
|
|
||||||
setHostSidebarOpen((v) => !v);
|
setHostSidebarOpen((v) => !v);
|
||||||
} else {
|
} else {
|
||||||
setMobileSidebarOpen((v) => !v);
|
setMobileSidebarOpen((v) => !v);
|
||||||
}
|
}
|
||||||
}, [closeHostSidebarPreview]);
|
}, []);
|
||||||
|
|
||||||
const applyWorkspaceScope = useCallback(
|
const applyWorkspaceScope = useCallback(
|
||||||
(scope: WorkspaceScopePayload) => {
|
(scope: WorkspaceScopePayload) => {
|
||||||
@@ -2574,13 +2483,7 @@ function Shell({
|
|||||||
archivedCount: sidebarArchivedTabKeys.length,
|
archivedCount: sidebarArchivedTabKeys.length,
|
||||||
defaultWorkspacePath: workspaces?.default_scope.project_path ?? null,
|
defaultWorkspacePath: workspaces?.default_scope.project_path ?? null,
|
||||||
};
|
};
|
||||||
const hostSidebarCollapsed = showHostChrome && !hostSidebarOpen;
|
const hostSidebarFlowWidth = hostSidebarOpen ? SIDEBAR_WIDTH : SIDEBAR_RAIL_WIDTH;
|
||||||
const showHostSidebarPreview =
|
|
||||||
showMainSidebar && hostSidebarCollapsed && hostSidebarPreviewOpen;
|
|
||||||
const hostSidebarFlowWidth = showHostChrome
|
|
||||||
? (hostSidebarOpen ? SIDEBAR_WIDTH : 0)
|
|
||||||
: (hostSidebarOpen ? SIDEBAR_WIDTH : SIDEBAR_RAIL_WIDTH);
|
|
||||||
const renderHostSidebarFlowContent = !showHostChrome || hostSidebarOpen;
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
document.documentElement.classList.toggle("native-host", showHostChrome);
|
document.documentElement.classList.toggle("native-host", showHostChrome);
|
||||||
@@ -2599,10 +2502,6 @@ function Shell({
|
|||||||
>
|
>
|
||||||
{showHostChrome ? (
|
{showHostChrome ? (
|
||||||
<HostChrome
|
<HostChrome
|
||||||
onToggleSidebar={showMainSidebar ? toggleHostSidebar : undefined}
|
|
||||||
onSidebarPreviewEnter={openHostSidebarPreview}
|
|
||||||
onSidebarPreviewLeave={scheduleHostSidebarPreviewClose}
|
|
||||||
sidebarOpen={hostSidebarOpen}
|
|
||||||
rightAction={
|
rightAction={
|
||||||
view === "chat" ? undefined : (
|
view === "chat" ? undefined : (
|
||||||
<Button
|
<Button
|
||||||
@@ -2640,7 +2539,6 @@ function Shell({
|
|||||||
width: hostSidebarFlowWidth,
|
width: hostSidebarFlowWidth,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{renderHostSidebarFlowContent ? (
|
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
"absolute inset-y-0 left-0 h-full w-full overflow-hidden",
|
"absolute inset-y-0 left-0 h-full w-full overflow-hidden",
|
||||||
@@ -2651,27 +2549,7 @@ function Shell({
|
|||||||
>
|
>
|
||||||
<Sidebar
|
<Sidebar
|
||||||
{...sidebarProps}
|
{...sidebarProps}
|
||||||
collapsed={!showHostChrome && !hostSidebarOpen}
|
collapsed={!hostSidebarOpen}
|
||||||
hostChromeInset={showHostChrome}
|
|
||||||
onCollapse={closeHostSidebar}
|
|
||||||
onExpand={openHostSidebar}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
</aside>
|
|
||||||
) : null}
|
|
||||||
|
|
||||||
{showHostSidebarPreview ? (
|
|
||||||
<aside
|
|
||||||
data-testid="host-sidebar-preview"
|
|
||||||
className="absolute inset-y-0 left-0 z-30 hidden overflow-hidden lg:block animate-in fade-in-0 slide-in-from-left-2 duration-150"
|
|
||||||
style={{ width: SIDEBAR_WIDTH }}
|
|
||||||
onMouseEnter={openHostSidebarPreview}
|
|
||||||
onMouseLeave={scheduleHostSidebarPreviewClose}
|
|
||||||
>
|
|
||||||
<div className="h-full w-full overflow-hidden host-sidebar-glass shadow-2xl">
|
|
||||||
<Sidebar
|
|
||||||
{...sidebarProps}
|
|
||||||
hostChromeInset={showHostChrome}
|
hostChromeInset={showHostChrome}
|
||||||
onCollapse={closeHostSidebar}
|
onCollapse={closeHostSidebar}
|
||||||
onExpand={openHostSidebar}
|
onExpand={openHostSidebar}
|
||||||
@@ -2782,7 +2660,6 @@ function Shell({
|
|||||||
theme={theme}
|
theme={theme}
|
||||||
onToggleTheme={toggle}
|
onToggleTheme={toggle}
|
||||||
hideSidebarToggleForHostChrome
|
hideSidebarToggleForHostChrome
|
||||||
hostChromeTitleInset={hostSidebarCollapsed}
|
|
||||||
hideHeader={false}
|
hideHeader={false}
|
||||||
workspaceScope={activeWorkspaceScope}
|
workspaceScope={activeWorkspaceScope}
|
||||||
workspaceDefaultScope={workspaces?.default_scope ?? null}
|
workspaceDefaultScope={workspaces?.default_scope ?? null}
|
||||||
@@ -2820,7 +2697,6 @@ function Shell({
|
|||||||
onToggleTheme={toggle}
|
onToggleTheme={toggle}
|
||||||
hideSidebarToggle={!context.active}
|
hideSidebarToggle={!context.active}
|
||||||
hideSidebarToggleForHostChrome={context.active}
|
hideSidebarToggleForHostChrome={context.active}
|
||||||
hostChromeTitleInset={hostSidebarCollapsed}
|
|
||||||
hideThemeButton={!context.active}
|
hideThemeButton={!context.active}
|
||||||
hideHeaderTitle
|
hideHeaderTitle
|
||||||
inlineHandle={workbenchPaneSessions.length > 1}
|
inlineHandle={workbenchPaneSessions.length > 1}
|
||||||
|
|||||||
@@ -130,13 +130,14 @@ export function Sidebar(props: SidebarProps) {
|
|||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
|
data-testid="sidebar-brand-row"
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex items-center px-3 pb-2.5",
|
"flex items-start px-3 pb-2.5 pt-3",
|
||||||
props.hostChromeInset ? "pt-[2.85rem]" : "pt-3",
|
|
||||||
collapsed ? "w-14 justify-start" : "justify-between",
|
collapsed ? "w-14 justify-start" : "justify-between",
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
|
data-testid="sidebar-brand-mark"
|
||||||
type="button"
|
type="button"
|
||||||
aria-label={collapsed ? toggleLabel : undefined}
|
aria-label={collapsed ? toggleLabel : undefined}
|
||||||
aria-hidden={collapsed ? undefined : true}
|
aria-hidden={collapsed ? undefined : true}
|
||||||
@@ -144,7 +145,8 @@ export function Sidebar(props: SidebarProps) {
|
|||||||
onClick={collapsed ? props.onExpand : undefined}
|
onClick={collapsed ? props.onExpand : undefined}
|
||||||
tabIndex={collapsed ? 0 : -1}
|
tabIndex={collapsed ? 0 : -1}
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex h-9 w-9 shrink-0 items-center justify-center overflow-hidden rounded-xl transition-colors",
|
"host-no-drag flex h-9 w-9 shrink-0 items-center justify-center overflow-hidden rounded-xl transition-colors",
|
||||||
|
props.hostChromeInset && "mt-5",
|
||||||
collapsed
|
collapsed
|
||||||
? "-ml-0.5 hover:bg-sidebar-accent/75"
|
? "-ml-0.5 hover:bg-sidebar-accent/75"
|
||||||
: "pointer-events-none -ml-0.5",
|
: "pointer-events-none -ml-0.5",
|
||||||
@@ -157,13 +159,13 @@ export function Sidebar(props: SidebarProps) {
|
|||||||
draggable={false}
|
draggable={false}
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
{!collapsed && !props.hostChromeInset && (
|
{!collapsed && (
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
size="icon"
|
size="icon"
|
||||||
aria-label={t("sidebar.collapse")}
|
aria-label={t("sidebar.collapse")}
|
||||||
onClick={props.onCollapse}
|
onClick={props.onCollapse}
|
||||||
className="h-7 w-7 rounded-lg text-muted-foreground/85 hover:bg-sidebar-accent/75 hover:text-sidebar-foreground"
|
className="host-no-drag h-7 w-7 rounded-lg text-muted-foreground/85 hover:bg-sidebar-accent/75 hover:text-sidebar-foreground"
|
||||||
>
|
>
|
||||||
<Menu className="h-3.5 w-3.5" />
|
<Menu className="h-3.5 w-3.5" />
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -454,6 +454,8 @@ describe("App layout", () => {
|
|||||||
const main = container.querySelector("main");
|
const main = container.querySelector("main");
|
||||||
expect(main).toBeInTheDocument();
|
expect(main).toBeInTheDocument();
|
||||||
expect(main).not.toHaveAttribute("style");
|
expect(main).not.toHaveAttribute("style");
|
||||||
|
expect(screen.getByTestId("sidebar-brand-row")).toHaveClass("pt-3");
|
||||||
|
expect(screen.getByTestId("sidebar-brand-mark")).not.toHaveClass("mt-5");
|
||||||
|
|
||||||
const asideClassNames = Array.from(container.querySelectorAll("aside")).map(
|
const asideClassNames = Array.from(container.querySelectorAll("aside")).map(
|
||||||
(el) => el.className,
|
(el) => el.className,
|
||||||
@@ -1609,7 +1611,7 @@ describe("App layout", () => {
|
|||||||
expect(document.title).toBe("自动任务 · nanobot");
|
expect(document.title).toBe("自动任务 · nanobot");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("fully collapses the native host sidebar and previews it on hover", async () => {
|
it("uses the shared sidebar controls and rail on the native host", async () => {
|
||||||
mockSessions = [
|
mockSessions = [
|
||||||
{
|
{
|
||||||
key: "websocket:chat-a",
|
key: "websocket:chat-a",
|
||||||
@@ -1632,36 +1634,25 @@ describe("App layout", () => {
|
|||||||
|
|
||||||
await waitFor(() => expect(connectSpy).toHaveBeenCalled());
|
await waitFor(() => expect(connectSpy).toHaveBeenCalled());
|
||||||
const flowSidebar = screen.getByTestId("host-sidebar-flow");
|
const flowSidebar = screen.getByTestId("host-sidebar-flow");
|
||||||
const toggle = screen.getByTestId("host-sidebar-toggle");
|
|
||||||
expect(flowSidebar).toHaveStyle({ width: "272px" });
|
expect(flowSidebar).toHaveStyle({ width: "272px" });
|
||||||
|
expect(screen.getByTestId("sidebar-brand-row")).toHaveClass("pt-3");
|
||||||
|
expect(screen.getByTestId("sidebar-brand-mark")).toHaveClass("mt-5");
|
||||||
|
expect(screen.queryByTestId("host-sidebar-toggle")).not.toBeInTheDocument();
|
||||||
expect(
|
expect(
|
||||||
screen.getByRole("navigation", { name: "Sidebar navigation" }),
|
screen.getByRole("navigation", { name: "Sidebar navigation" }),
|
||||||
).toBeInTheDocument();
|
).toBeInTheDocument();
|
||||||
|
|
||||||
fireEvent.click(toggle);
|
fireEvent.click(screen.getByRole("button", { name: "Collapse sidebar" }));
|
||||||
await waitFor(() => expect(flowSidebar).toHaveStyle({ width: "0px" }));
|
await waitFor(() => expect(flowSidebar).toHaveStyle({ width: "56px" }));
|
||||||
expect(
|
expect(
|
||||||
screen.queryByRole("navigation", { name: "Sidebar navigation" }),
|
screen.getByRole("navigation", { name: "Sidebar navigation" }),
|
||||||
).not.toBeInTheDocument();
|
|
||||||
|
|
||||||
fireEvent.mouseEnter(toggle);
|
|
||||||
const previewSidebar = await screen.findByTestId("host-sidebar-preview");
|
|
||||||
expect(flowSidebar).toHaveStyle({ width: "0px" });
|
|
||||||
expect(previewSidebar).toHaveStyle({ width: "272px" });
|
|
||||||
expect(
|
|
||||||
within(previewSidebar).getByRole("navigation", {
|
|
||||||
name: "Sidebar navigation",
|
|
||||||
}),
|
|
||||||
).toBeInTheDocument();
|
).toBeInTheDocument();
|
||||||
|
|
||||||
fireEvent.click(toggle);
|
fireEvent.click(
|
||||||
await waitFor(() =>
|
within(screen.getByRole("navigation", { name: "Sidebar navigation" }))
|
||||||
expect(screen.queryByTestId("host-sidebar-preview")).not.toBeInTheDocument(),
|
.getByRole("button", { name: "Toggle sidebar" }),
|
||||||
);
|
);
|
||||||
expect(flowSidebar).toHaveStyle({ width: "272px" });
|
await waitFor(() => expect(flowSidebar).toHaveStyle({ width: "272px" }));
|
||||||
expect(
|
|
||||||
screen.getByRole("navigation", { name: "Sidebar navigation" }),
|
|
||||||
).toBeInTheDocument();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("switches to the next session when deleting the active chat", async () => {
|
it("switches to the next session when deleting the active chat", async () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user