feat(frontend): add resizable activity split

This commit is contained in:
User
2026-07-15 15:04:15 +02:00
parent 30e76a968d
commit d177e1c0af
5 changed files with 313 additions and 13 deletions
+26 -2
View File
@@ -3,6 +3,7 @@ import { useSessionStore } from "../store/sessionStore";
import { WidgetHost } from "./WidgetHost";
import { CentralStatus } from "./CentralStatus";
import { ModelActivityPanel } from "./ModelActivityPanel";
import { useActivityPanelResize } from "./useActivityPanelResize";
import { NavSessions } from "./NavSessions";
import { SessionMenu } from "./SessionMenu";
import { SessionDocumentsPanel } from "./SessionDocumentsPanel";
@@ -23,6 +24,7 @@ import {
import type { SessionSummary } from "../api/types";
import { useQuery, useQueryClient } from "@tanstack/react-query";
import { useEffect, useMemo, useRef, useState } from "react";
import type { CSSProperties } from "react";
/**
* The page is designed to live INSIDE the Omics Portal chrome (its left sidebar
@@ -31,6 +33,10 @@ import { useEffect, useMemo, useRef, useState } from "react";
* portal's left sidebar, and the workflow phases ride a slim strip above the chat.
*/
export function AppShell() {
const { containerRef, panelWidth, resizing, separatorProps } = useActivityPanelResize();
const activityWidthStyle = {
"--activity-panel-width": `${panelWidth}px`,
} as CSSProperties;
const [activeSessionId, setActiveSessionId] = useState<string | null>(null);
const activeSessionIdRef = useRef<string | null>(null);
const resumeInvocationRef = useRef(0);
@@ -364,9 +370,15 @@ export function AppShell() {
return (
<div
ref={containerRef}
style={activityWidthStyle}
data-testid="app-shell"
data-activity-layout={showActivity ? "open" : "closed"}
className="flex h-screen bg-background text-foreground"
data-activity-resizing={resizing}
className={[
"flex h-screen bg-background text-foreground",
resizing ? "select-none cursor-col-resize" : "",
].join(" ")}
>
{panelSession && (
<SessionDocumentsPanel
@@ -376,9 +388,21 @@ export function AppShell() {
/>
)}
{showActivity && <ModelActivityPanel onClose={() => setShowActivity(false)} />}
{showActivity && (
<div className="relative hidden w-0 shrink-0 lg:block">
<div
{...separatorProps}
data-testid="activity-resize-handle"
data-dragging={resizing}
className="group absolute inset-y-0 left-1/2 z-20 w-3 -translate-x-1/2 touch-none cursor-col-resize outline-none"
>
<span className="absolute inset-y-0 left-1/2 w-px -translate-x-1/2 bg-border transition-colors group-hover:bg-primary/60 group-focus-visible:bg-primary group-data-[dragging=true]:bg-primary" />
</div>
</div>
)}
{/* Conversation column */}
<div className={["flex min-w-0 flex-col", showActivity ? "w-3/5 shrink-0" : "flex-1"].join(" ")}>
<div data-testid="conversation-column" className="flex min-w-0 flex-1 flex-col">
{activeSessionId && (
<div className="relative shrink-0 border-b border-border/70 bg-background/80 px-6 py-2.5 backdrop-blur">
{/* Arrow toggle for the left Model-activity panel: → opens it, ← closes it. */}