mirror of
https://github.com/rowboatlabs/rowboat.git
synced 2026-06-12 19:55:19 +02:00
Fix panel resizing issues
This commit is contained in:
parent
2e8e3c89cb
commit
c46468be90
2 changed files with 118 additions and 109 deletions
|
|
@ -1,6 +1,7 @@
|
|||
"use client";
|
||||
import React from "react";
|
||||
import { Button, Dropdown, DropdownItem, DropdownMenu, DropdownTrigger, Spinner, Tooltip, Input } from "@heroui/react";
|
||||
import { Button as CustomButton } from "@/components/ui/button";
|
||||
import { RadioIcon, RedoIcon, UndoIcon, RocketIcon, PenLine, AlertTriangle, DownloadIcon, SettingsIcon, ChevronDownIcon, ZapIcon, Clock, Plug } from "lucide-react";
|
||||
import { useParams, useRouter } from "next/navigation";
|
||||
|
||||
|
|
@ -103,22 +104,28 @@ export function TopBar({
|
|||
<div className="flex items-center gap-2">
|
||||
|
||||
{!isLive && <>
|
||||
<button
|
||||
className="p-1 text-gray-400 hover:text-black hover:cursor-pointer"
|
||||
title="Undo"
|
||||
disabled={!canUndo}
|
||||
<CustomButton
|
||||
variant="primary"
|
||||
size="sm"
|
||||
onClick={onUndo}
|
||||
disabled={!canUndo}
|
||||
className="bg-gray-50 text-gray-700 hover:bg-gray-100 disabled:bg-gray-25 disabled:text-gray-400"
|
||||
showHoverContent={true}
|
||||
hoverContent="Undo"
|
||||
>
|
||||
<UndoIcon size={16} />
|
||||
</button>
|
||||
<button
|
||||
className="p-1 text-gray-400 hover:text-black hover:cursor-pointer"
|
||||
title="Redo"
|
||||
disabled={!canRedo}
|
||||
<UndoIcon className="w-4 h-4" />
|
||||
</CustomButton>
|
||||
<CustomButton
|
||||
variant="primary"
|
||||
size="sm"
|
||||
onClick={onRedo}
|
||||
disabled={!canRedo}
|
||||
className="bg-gray-50 text-gray-700 hover:bg-gray-100 disabled:bg-gray-25 disabled:text-gray-400"
|
||||
showHoverContent={true}
|
||||
hoverContent="Redo"
|
||||
>
|
||||
<RedoIcon size={16} />
|
||||
</button>
|
||||
<RedoIcon className="w-4 h-4" />
|
||||
</CustomButton>
|
||||
</>}
|
||||
|
||||
{/* Deploy CTA - always visible */}
|
||||
|
|
|
|||
|
|
@ -1483,7 +1483,11 @@ export function WorkflowEditor({
|
|||
|
||||
{/* Content Area */}
|
||||
<ResizablePanelGroup direction="horizontal" className="flex-1 flex overflow-auto gap-1 rounded-xl bg-zinc-50 dark:bg-zinc-900">
|
||||
<ResizablePanel minSize={10} defaultSize={PANEL_RATIOS.entityList}>
|
||||
<ResizablePanel
|
||||
key={`entity-list-${state.present.selection ? '3-pane' : '2-pane'}`}
|
||||
minSize={10}
|
||||
defaultSize={PANEL_RATIOS.entityList}
|
||||
>
|
||||
<div className="flex flex-col h-full">
|
||||
<EntityList
|
||||
ref={entityListRef}
|
||||
|
|
@ -1536,107 +1540,105 @@ export function WorkflowEditor({
|
|||
/>
|
||||
</div>
|
||||
</ResizablePanel>
|
||||
<ResizableHandle withHandle className="w-[3px] bg-transparent" />
|
||||
<ResizableHandle withHandle className={`w-[3px] bg-transparent ${!state.present.selection ? 'hidden' : ''}`} />
|
||||
|
||||
{/* Config Panel - only show when there's a selection */}
|
||||
{state.present.selection && (
|
||||
<>
|
||||
<ResizablePanel
|
||||
minSize={20}
|
||||
defaultSize={50}
|
||||
className="overflow-auto"
|
||||
>
|
||||
{state.present.selection?.type === "agent" && <AgentConfig
|
||||
key={`agent-${state.present.workflow.agents.findIndex(agent => agent.name === state.present.selection!.name)}`}
|
||||
projectId={projectId}
|
||||
workflow={state.present.workflow}
|
||||
agent={state.present.workflow.agents.find((agent) => agent.name === state.present.selection!.name)!}
|
||||
usedAgentNames={new Set(state.present.workflow.agents.filter((agent) => agent.name !== state.present.selection!.name).map((agent) => agent.name))}
|
||||
usedPipelineNames={new Set((state.present.workflow.pipelines || []).map((pipeline) => pipeline.name))}
|
||||
agents={state.present.workflow.agents}
|
||||
tools={state.present.workflow.tools}
|
||||
prompts={state.present.workflow.prompts}
|
||||
dataSources={dataSources}
|
||||
handleUpdate={(update) => { dispatchGuarded({ type: "update_agent", name: state.present.selection!.name, agent: update }); }}
|
||||
handleClose={handleUnselectAgent}
|
||||
useRag={useRag}
|
||||
triggerCopilotChat={triggerCopilotChat}
|
||||
eligibleModels={eligibleModels === "*" ? "*" : eligibleModels.agentModels}
|
||||
onOpenDataSourcesModal={handleOpenDataSourcesModal}
|
||||
/>}
|
||||
{state.present.selection?.type === "tool" && (() => {
|
||||
const selectedTool = state.present.workflow.tools.find(
|
||||
(tool) => tool.name === state.present.selection!.name
|
||||
);
|
||||
return <ToolConfig
|
||||
key={state.present.selection.name}
|
||||
tool={selectedTool!}
|
||||
usedToolNames={new Set([
|
||||
...state.present.workflow.tools.filter((tool) => tool.name !== state.present.selection!.name).map((tool) => tool.name),
|
||||
])}
|
||||
handleUpdate={(update) => { dispatchGuarded({ type: "update_tool", name: state.present.selection!.name, tool: update }); }}
|
||||
handleClose={handleUnselectTool}
|
||||
/>;
|
||||
})()}
|
||||
{state.present.selection?.type === "prompt" && <PromptConfig
|
||||
key={state.present.selection.name}
|
||||
prompt={state.present.workflow.prompts.find((prompt) => prompt.name === state.present.selection!.name)!}
|
||||
agents={state.present.workflow.agents}
|
||||
tools={state.present.workflow.tools}
|
||||
prompts={state.present.workflow.prompts}
|
||||
usedPromptNames={new Set(state.present.workflow.prompts.filter((prompt) => prompt.name !== state.present.selection!.name).map((prompt) => prompt.name))}
|
||||
handleUpdate={(update) => { dispatchGuarded({ type: "update_prompt", name: state.present.selection!.name, prompt: update }); }}
|
||||
handleClose={handleUnselectPrompt}
|
||||
/>}
|
||||
{state.present.selection?.type === "datasource" && <DataSourceConfig
|
||||
key={state.present.selection.name}
|
||||
dataSourceId={state.present.selection.name}
|
||||
handleClose={() => dispatch({ type: "unselect_datasource" })}
|
||||
onDataSourceUpdate={onDataSourcesUpdated}
|
||||
/>}
|
||||
{state.present.selection?.type === "pipeline" && <PipelineConfig
|
||||
key={state.present.selection.name}
|
||||
projectId={projectId}
|
||||
workflow={state.present.workflow}
|
||||
pipeline={state.present.workflow.pipelines?.find((pipeline) => pipeline.name === state.present.selection!.name)!}
|
||||
usedPipelineNames={new Set((state.present.workflow.pipelines || []).filter((pipeline) => pipeline.name !== state.present.selection!.name).map((pipeline) => pipeline.name))}
|
||||
usedAgentNames={new Set(state.present.workflow.agents.map((agent) => agent.name))}
|
||||
agents={state.present.workflow.agents}
|
||||
pipelines={state.present.workflow.pipelines || []}
|
||||
handleUpdate={handleUpdatePipeline.bind(null, state.present.selection.name)}
|
||||
handleClose={() => dispatch({ type: "unselect_pipeline" })}
|
||||
/>}
|
||||
{state.present.selection?.type === "visualise" && (
|
||||
<Panel
|
||||
title={
|
||||
<div className="flex items-center justify-between w-full">
|
||||
<div className="text-base font-semibold text-gray-900 dark:text-gray-100">
|
||||
Agent Graph Visualizer
|
||||
</div>
|
||||
<CustomButton
|
||||
variant="secondary"
|
||||
size="sm"
|
||||
onClick={handleHideVisualise}
|
||||
showHoverContent={true}
|
||||
hoverContent="Close"
|
||||
>
|
||||
<XIcon className="w-4 h-4" />
|
||||
</CustomButton>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<div className="h-full overflow-hidden">
|
||||
<AgentGraphVisualizer workflow={state.present.workflow} />
|
||||
{/* Config Panel - always rendered, visibility controlled */}
|
||||
<ResizablePanel
|
||||
minSize={20}
|
||||
defaultSize={45}
|
||||
className={`overflow-auto ${!state.present.selection ? 'hidden' : ''}`}
|
||||
>
|
||||
{state.present.selection?.type === "agent" && <AgentConfig
|
||||
key={`agent-${state.present.workflow.agents.findIndex(agent => agent.name === state.present.selection!.name)}`}
|
||||
projectId={projectId}
|
||||
workflow={state.present.workflow}
|
||||
agent={state.present.workflow.agents.find((agent) => agent.name === state.present.selection!.name)!}
|
||||
usedAgentNames={new Set(state.present.workflow.agents.filter((agent) => agent.name !== state.present.selection!.name).map((agent) => agent.name))}
|
||||
usedPipelineNames={new Set((state.present.workflow.pipelines || []).map((pipeline) => pipeline.name))}
|
||||
agents={state.present.workflow.agents}
|
||||
tools={state.present.workflow.tools}
|
||||
prompts={state.present.workflow.prompts}
|
||||
dataSources={dataSources}
|
||||
handleUpdate={(update) => { dispatchGuarded({ type: "update_agent", name: state.present.selection!.name, agent: update }); }}
|
||||
handleClose={handleUnselectAgent}
|
||||
useRag={useRag}
|
||||
triggerCopilotChat={triggerCopilotChat}
|
||||
eligibleModels={eligibleModels === "*" ? "*" : eligibleModels.agentModels}
|
||||
onOpenDataSourcesModal={handleOpenDataSourcesModal}
|
||||
/>}
|
||||
{state.present.selection?.type === "tool" && (() => {
|
||||
const selectedTool = state.present.workflow.tools.find(
|
||||
(tool) => tool.name === state.present.selection!.name
|
||||
);
|
||||
return <ToolConfig
|
||||
key={state.present.selection.name}
|
||||
tool={selectedTool!}
|
||||
usedToolNames={new Set([
|
||||
...state.present.workflow.tools.filter((tool) => tool.name !== state.present.selection!.name).map((tool) => tool.name),
|
||||
])}
|
||||
handleUpdate={(update) => { dispatchGuarded({ type: "update_tool", name: state.present.selection!.name, tool: update }); }}
|
||||
handleClose={handleUnselectTool}
|
||||
/>;
|
||||
})()}
|
||||
{state.present.selection?.type === "prompt" && <PromptConfig
|
||||
key={state.present.selection.name}
|
||||
prompt={state.present.workflow.prompts.find((prompt) => prompt.name === state.present.selection!.name)!}
|
||||
agents={state.present.workflow.agents}
|
||||
tools={state.present.workflow.tools}
|
||||
prompts={state.present.workflow.prompts}
|
||||
usedPromptNames={new Set(state.present.workflow.prompts.filter((prompt) => prompt.name !== state.present.selection!.name).map((prompt) => prompt.name))}
|
||||
handleUpdate={(update) => { dispatchGuarded({ type: "update_prompt", name: state.present.selection!.name, prompt: update }); }}
|
||||
handleClose={handleUnselectPrompt}
|
||||
/>}
|
||||
{state.present.selection?.type === "datasource" && <DataSourceConfig
|
||||
key={state.present.selection.name}
|
||||
dataSourceId={state.present.selection.name}
|
||||
handleClose={() => dispatch({ type: "unselect_datasource" })}
|
||||
onDataSourceUpdate={onDataSourcesUpdated}
|
||||
/>}
|
||||
{state.present.selection?.type === "pipeline" && <PipelineConfig
|
||||
key={state.present.selection.name}
|
||||
projectId={projectId}
|
||||
workflow={state.present.workflow}
|
||||
pipeline={state.present.workflow.pipelines?.find((pipeline) => pipeline.name === state.present.selection!.name)!}
|
||||
usedPipelineNames={new Set((state.present.workflow.pipelines || []).filter((pipeline) => pipeline.name !== state.present.selection!.name).map((pipeline) => pipeline.name))}
|
||||
usedAgentNames={new Set(state.present.workflow.agents.map((agent) => agent.name))}
|
||||
agents={state.present.workflow.agents}
|
||||
pipelines={state.present.workflow.pipelines || []}
|
||||
handleUpdate={handleUpdatePipeline.bind(null, state.present.selection.name)}
|
||||
handleClose={() => dispatch({ type: "unselect_pipeline" })}
|
||||
/>}
|
||||
{state.present.selection?.type === "visualise" && (
|
||||
<Panel
|
||||
title={
|
||||
<div className="flex items-center justify-between w-full">
|
||||
<div className="text-base font-semibold text-gray-900 dark:text-gray-100">
|
||||
Agent Graph Visualizer
|
||||
</div>
|
||||
</Panel>
|
||||
)}
|
||||
</ResizablePanel>
|
||||
<ResizableHandle withHandle className="w-[3px] bg-transparent" />
|
||||
</>
|
||||
)}
|
||||
<CustomButton
|
||||
variant="secondary"
|
||||
size="sm"
|
||||
onClick={handleHideVisualise}
|
||||
showHoverContent={true}
|
||||
hoverContent="Close"
|
||||
>
|
||||
<XIcon className="w-4 h-4" />
|
||||
</CustomButton>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<div className="h-full overflow-hidden">
|
||||
<AgentGraphVisualizer workflow={state.present.workflow} />
|
||||
</div>
|
||||
</Panel>
|
||||
)}
|
||||
</ResizablePanel>
|
||||
{/* Second handle - always show (between config and chat panels) */}
|
||||
<ResizableHandle withHandle className="w-[3px] bg-transparent" />
|
||||
|
||||
{/* ChatApp/Copilot Panel - always visible */}
|
||||
<ResizablePanel
|
||||
key={`chat-panel-${state.present.selection ? '3-pane' : '2-pane'}`}
|
||||
minSize={20}
|
||||
defaultSize={state.present.selection ? 30 : PANEL_RATIOS.chatApp + PANEL_RATIOS.copilot}
|
||||
className="overflow-auto"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue