mirror of
https://github.com/rowboatlabs/rowboat.git
synced 2026-06-12 19:55:19 +02:00
Display copilot and playground as toggles
This commit is contained in:
parent
3d36884c73
commit
251198225b
8 changed files with 225 additions and 171 deletions
|
|
@ -269,7 +269,7 @@ const App = forwardRef<{ handleCopyChat: () => void; handleUserMessage: (message
|
|||
toolQuery={toolQuery}
|
||||
/>
|
||||
</div>
|
||||
<div className="shrink-0 px-1">
|
||||
<div className="shrink-0 px-0 pb-0">
|
||||
{responseError && (
|
||||
<div className="mb-4 p-2 bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-lg flex gap-2 justify-between items-center text-sm">
|
||||
<p className="text-red-600 dark:text-red-400">{responseError}</p>
|
||||
|
|
@ -322,6 +322,8 @@ export const Copilot = forwardRef<{ handleUserMessage: (message: string) => void
|
|||
dispatch: (action: WorkflowDispatch) => void;
|
||||
isInitialState?: boolean;
|
||||
dataSources?: z.infer<typeof DataSource>[];
|
||||
activePanel: 'playground' | 'copilot';
|
||||
onTogglePanel: () => void;
|
||||
}>(({
|
||||
projectId,
|
||||
workflow,
|
||||
|
|
@ -329,6 +331,8 @@ export const Copilot = forwardRef<{ handleUserMessage: (message: string) => void
|
|||
dispatch,
|
||||
isInitialState = false,
|
||||
dataSources,
|
||||
activePanel,
|
||||
onTogglePanel,
|
||||
}, ref) => {
|
||||
const [copilotKey, setCopilotKey] = useState(0);
|
||||
const [showCopySuccess, setShowCopySuccess] = useState(false);
|
||||
|
|
@ -365,8 +369,34 @@ export const Copilot = forwardRef<{ handleUserMessage: (message: string) => void
|
|||
<Panel
|
||||
variant="copilot"
|
||||
tourTarget="copilot"
|
||||
icon={<Sparkles className="w-5 h-5 text-indigo-600 dark:text-indigo-400" />}
|
||||
title="Skipper"
|
||||
title={
|
||||
<div className="flex items-center">
|
||||
<div className="flex items-center gap-2 rounded-lg p-1 bg-blue-50/70 dark:bg-blue-900/30">
|
||||
<button
|
||||
onClick={onTogglePanel}
|
||||
className={`flex items-center gap-2 px-3 py-1.5 rounded-md text-sm font-medium transition-all duration-200 ${
|
||||
activePanel === 'copilot'
|
||||
? 'bg-white dark:bg-zinc-700 text-indigo-700 dark:text-indigo-300 shadow-md border border-indigo-200 dark:border-indigo-700'
|
||||
: 'text-zinc-600 dark:text-zinc-400 hover:text-zinc-900 dark:hover:text-zinc-200 hover:bg-zinc-100/60 dark:hover:bg-zinc-800/60'
|
||||
}`}
|
||||
>
|
||||
<span className="text-base">✨</span>
|
||||
Build
|
||||
</button>
|
||||
<button
|
||||
onClick={onTogglePanel}
|
||||
className={`flex items-center gap-2 px-3 py-1.5 rounded-md text-sm font-medium transition-all duration-200 ${
|
||||
activePanel === 'playground'
|
||||
? 'bg-white dark:bg-zinc-700 text-indigo-700 dark:text-indigo-300 shadow-md border border-indigo-200 dark:border-indigo-700'
|
||||
: 'text-zinc-600 dark:text-zinc-400 hover:text-zinc-900 dark:hover:text-zinc-200 hover:bg-zinc-100/60 dark:hover:bg-zinc-800/60'
|
||||
}`}
|
||||
>
|
||||
<span className="text-base">💬</span>
|
||||
Test
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
subtitle="Build your assistant"
|
||||
rightActions={
|
||||
<div className="flex items-center gap-2">
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@ export function App({
|
|||
onPanelClick,
|
||||
triggerCopilotChat,
|
||||
isLiveWorkflow,
|
||||
activePanel,
|
||||
onTogglePanel,
|
||||
}: {
|
||||
hidden?: boolean;
|
||||
projectId: string;
|
||||
|
|
@ -25,6 +27,8 @@ export function App({
|
|||
onPanelClick?: () => void;
|
||||
triggerCopilotChat?: (message: string) => void;
|
||||
isLiveWorkflow: boolean;
|
||||
activePanel: 'playground' | 'copilot';
|
||||
onTogglePanel: () => void;
|
||||
}) {
|
||||
const [counter, setCounter] = useState<number>(0);
|
||||
const [showDebugMessages, setShowDebugMessages] = useState<boolean>(true);
|
||||
|
|
@ -56,8 +60,34 @@ export function App({
|
|||
className={`${hidden ? 'hidden' : 'block'}`}
|
||||
variant="playground"
|
||||
tourTarget="playground"
|
||||
icon={<MessageCircle className="w-5 h-5 text-blue-600 dark:text-blue-400" />}
|
||||
title="Chat"
|
||||
title={
|
||||
<div className="flex items-center">
|
||||
<div className="flex items-center gap-2 rounded-lg p-1 bg-blue-50/70 dark:bg-blue-900/30">
|
||||
<button
|
||||
onClick={onTogglePanel}
|
||||
className={`flex items-center gap-2 px-3 py-1.5 rounded-md text-sm font-medium transition-all duration-200 ${
|
||||
activePanel === 'copilot'
|
||||
? 'bg-white dark:bg-zinc-700 text-indigo-700 dark:text-indigo-300 shadow-md border border-indigo-200 dark:border-indigo-700'
|
||||
: 'text-zinc-600 dark:text-zinc-400 hover:text-zinc-900 dark:hover:text-zinc-200 hover:bg-zinc-100/60 dark:hover:bg-zinc-800/60'
|
||||
}`}
|
||||
>
|
||||
<span className="text-base">✨</span>
|
||||
Build
|
||||
</button>
|
||||
<button
|
||||
onClick={onTogglePanel}
|
||||
className={`flex items-center gap-2 px-3 py-1.5 rounded-md text-sm font-medium transition-all duration-200 ${
|
||||
activePanel === 'playground'
|
||||
? 'bg-white dark:bg-zinc-700 text-indigo-700 dark:text-indigo-300 shadow-md border border-indigo-200 dark:border-indigo-700'
|
||||
: 'text-zinc-600 dark:text-zinc-400 hover:text-zinc-900 dark:hover:text-zinc-200 hover:bg-zinc-100/60 dark:hover:bg-zinc-800/60'
|
||||
}`}
|
||||
>
|
||||
<span className="text-base">💬</span>
|
||||
Test
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
subtitle="Chat with your assistant"
|
||||
rightActions={
|
||||
<div className="flex items-center gap-2">
|
||||
|
|
|
|||
|
|
@ -425,7 +425,7 @@ export function Chat({
|
|||
<ChevronDownIcon className="w-5 h-5" strokeWidth={2.2} />
|
||||
</button>
|
||||
)}
|
||||
<div className="bg-white dark:bg-zinc-900 pt-4 pb-2">
|
||||
<div className="bg-white dark:bg-zinc-900 pt-4 pb-6">
|
||||
{showSuccessMessage && (
|
||||
<div className="mb-4 p-3 bg-green-50 dark:bg-green-900/20 border border-green-200 dark:border-green-800
|
||||
rounded-lg flex gap-2 justify-between items-center">
|
||||
|
|
|
|||
|
|
@ -14,14 +14,14 @@ interface TopBarProps {
|
|||
showCopySuccess: boolean;
|
||||
canUndo: boolean;
|
||||
canRedo: boolean;
|
||||
showCopilot: boolean;
|
||||
activePanel: 'playground' | 'copilot';
|
||||
onUndo: () => void;
|
||||
onRedo: () => void;
|
||||
onDownloadJSON: () => void;
|
||||
onPublishWorkflow: () => void;
|
||||
onChangeMode: (mode: 'draft' | 'live') => void;
|
||||
onRevertToLive: () => void;
|
||||
onToggleCopilot: () => void;
|
||||
onTogglePanel: () => void;
|
||||
}
|
||||
|
||||
export function TopBar({
|
||||
|
|
@ -34,14 +34,14 @@ export function TopBar({
|
|||
showCopySuccess,
|
||||
canUndo,
|
||||
canRedo,
|
||||
showCopilot,
|
||||
activePanel,
|
||||
onUndo,
|
||||
onRedo,
|
||||
onDownloadJSON,
|
||||
onPublishWorkflow,
|
||||
onChangeMode,
|
||||
onRevertToLive,
|
||||
onToggleCopilot,
|
||||
onTogglePanel,
|
||||
}: TopBarProps) {
|
||||
const router = useRouter();
|
||||
const params = useParams();
|
||||
|
|
@ -70,47 +70,29 @@ export function TopBar({
|
|||
classNames={{
|
||||
base: "max-w-xs",
|
||||
input: "text-base font-semibold px-2",
|
||||
inputWrapper: "min-h-[28px] h-[28px] border-gray-200 dark:border-gray-700 px-0"
|
||||
inputWrapper: "min-h-[36px] h-[36px] border-gray-200 dark:border-gray-700 px-0"
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="h-4 w-px bg-gray-300 dark:bg-gray-600"></div>
|
||||
|
||||
<div className="flex items-center gap-2">
|
||||
{publishing && <Spinner size="sm" />}
|
||||
{isLive && <div className="bg-green-100 dark:bg-green-900/30 text-green-700 dark:text-green-400 px-2 py-1 rounded-md text-xs font-medium flex items-center gap-1.5">
|
||||
<RadioIcon size={16} />
|
||||
Live workflow
|
||||
</div>}
|
||||
{!isLive && <div className="bg-yellow-50 dark:bg-yellow-900/20 text-yellow-600 dark:text-yellow-400 px-2 py-1 rounded-md text-xs font-medium flex items-center gap-1.5">
|
||||
<PenLine size={16} />
|
||||
Draft workflow
|
||||
</div>}
|
||||
|
||||
{/* Download JSON icon button, with tooltip, to the left of the menu */}
|
||||
<Tooltip content="Download Assistant JSON">
|
||||
<button
|
||||
onClick={onDownloadJSON}
|
||||
className="p-1.5 text-indigo-600 hover:text-indigo-700 dark:text-indigo-400 dark:hover:text-indigo-300 transition-colors"
|
||||
aria-label="Download JSON"
|
||||
type="button"
|
||||
>
|
||||
<DownloadIcon size={20} />
|
||||
</button>
|
||||
</Tooltip>
|
||||
</div>
|
||||
{/* Show divider and CTA only in live view */}
|
||||
{isLive && <div className="h-4 w-px bg-gray-300 dark:bg-gray-600"></div>}
|
||||
{isLive ? (
|
||||
<Button
|
||||
variant="solid"
|
||||
size="md"
|
||||
onPress={() => onChangeMode('draft')}
|
||||
className="gap-2 px-4 bg-gray-100 hover:bg-gray-200 text-gray-700 dark:bg-gray-700 dark:hover:bg-gray-600 dark:text-gray-300 font-medium text-sm border border-gray-200 dark:border-gray-600 shadow-sm"
|
||||
startContent={<PenLine size={16} />}
|
||||
>
|
||||
Switch to draft
|
||||
</Button>
|
||||
) : null}
|
||||
</div>
|
||||
{showCopySuccess && <div className="flex items-center gap-2">
|
||||
<div className="text-green-500">Copied to clipboard</div>
|
||||
</div>}
|
||||
<div className="flex items-center gap-2">
|
||||
{isLive && <div className="flex items-center gap-2 absolute left-1/2 transform -translate-x-1/2">
|
||||
<div className="bg-amber-50 dark:bg-amber-900/20 text-amber-700 dark:text-amber-400 px-3 py-1.5 rounded-md text-sm font-medium flex items-center gap-2">
|
||||
<AlertTriangle size={16} />
|
||||
This version is locked. Changes applied will not be reflected.
|
||||
</div>
|
||||
</div>}
|
||||
|
||||
{!isLive && <>
|
||||
<button
|
||||
|
|
@ -132,44 +114,66 @@ export function TopBar({
|
|||
</>}
|
||||
|
||||
{/* Deploy CTA - always visible */}
|
||||
<div className="flex">
|
||||
<div className="flex items-center gap-3">
|
||||
{isLive ? (
|
||||
<Dropdown>
|
||||
<DropdownTrigger>
|
||||
<Button
|
||||
variant="solid"
|
||||
size="md"
|
||||
className="gap-2 px-4 bg-indigo-600 hover:bg-indigo-700 text-white font-semibold text-sm"
|
||||
startContent={<Plug size={16} />}
|
||||
>
|
||||
Use Assistant
|
||||
<ChevronDownIcon size={14} />
|
||||
</Button>
|
||||
</DropdownTrigger>
|
||||
<DropdownMenu aria-label="Assistant access options">
|
||||
<DropdownItem
|
||||
key="api-sdk"
|
||||
startContent={<SettingsIcon size={16} />}
|
||||
onPress={() => { if (projectId) { router.push(`/projects/${projectId}/config`); } }}
|
||||
>
|
||||
API & SDK Settings
|
||||
</DropdownItem>
|
||||
<DropdownItem
|
||||
key="manage-triggers"
|
||||
startContent={<ZapIcon size={16} />}
|
||||
onPress={() => { if (projectId) { router.push(`/projects/${projectId}/manage-triggers`); } }}
|
||||
<>
|
||||
<Dropdown>
|
||||
<DropdownTrigger>
|
||||
<Button
|
||||
variant="solid"
|
||||
size="md"
|
||||
className="gap-2 px-4 bg-blue-50 hover:bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:hover:bg-blue-900/50 dark:text-blue-400 font-semibold text-sm border border-blue-200 dark:border-blue-700 shadow-sm"
|
||||
startContent={<Plug size={16} />}
|
||||
>
|
||||
Manage Triggers
|
||||
</DropdownItem>
|
||||
</DropdownMenu>
|
||||
</Dropdown>
|
||||
Use Assistant
|
||||
<ChevronDownIcon size={14} />
|
||||
</Button>
|
||||
</DropdownTrigger>
|
||||
<DropdownMenu aria-label="Assistant access options">
|
||||
<DropdownItem
|
||||
key="api-sdk"
|
||||
startContent={<SettingsIcon size={16} />}
|
||||
onPress={() => { if (projectId) { router.push(`/projects/${projectId}/config`); } }}
|
||||
>
|
||||
API & SDK Settings
|
||||
</DropdownItem>
|
||||
<DropdownItem
|
||||
key="manage-triggers"
|
||||
startContent={<ZapIcon size={16} />}
|
||||
onPress={() => { if (projectId) { router.push(`/projects/${projectId}/manage-triggers`); } }}
|
||||
>
|
||||
Manage Triggers
|
||||
</DropdownItem>
|
||||
</DropdownMenu>
|
||||
</Dropdown>
|
||||
|
||||
{/* Live workflow label moved here */}
|
||||
<div className="flex items-center gap-2 ml-2">
|
||||
{publishing && <Spinner size="sm" />}
|
||||
<div className="bg-green-100 dark:bg-green-900/30 text-green-700 dark:text-green-400 px-2 py-1 rounded-md text-xs font-medium flex items-center gap-1.5">
|
||||
<RadioIcon size={16} />
|
||||
Live workflow
|
||||
</div>
|
||||
<Tooltip content="Download Assistant JSON">
|
||||
<button
|
||||
onClick={onDownloadJSON}
|
||||
className="p-1.5 text-indigo-600 hover:text-indigo-700 dark:text-indigo-400 dark:hover:text-indigo-300 transition-colors"
|
||||
aria-label="Download JSON"
|
||||
type="button"
|
||||
>
|
||||
<DownloadIcon size={20} />
|
||||
</button>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<div className="flex">
|
||||
<Button
|
||||
variant="solid"
|
||||
size="md"
|
||||
onPress={onPublishWorkflow}
|
||||
className="gap-2 px-4 bg-green-600 hover:bg-green-700 text-white font-semibold text-sm rounded-r-none"
|
||||
className="gap-2 px-4 bg-green-100 hover:bg-green-200 text-green-800 font-semibold text-sm rounded-r-none border border-green-300 shadow-sm"
|
||||
startContent={<RocketIcon size={16} />}
|
||||
data-tour-target="deploy"
|
||||
>
|
||||
|
|
@ -180,7 +184,7 @@ export function TopBar({
|
|||
<Button
|
||||
variant="solid"
|
||||
size="md"
|
||||
className="min-w-0 px-2 bg-green-600 hover:bg-green-700 border-l-1 border-green-500 text-white font-semibold text-sm rounded-l-none"
|
||||
className="min-w-0 px-2 bg-green-100 hover:bg-green-200 text-green-800 rounded-l-none border border-l-0 border-green-300 shadow-sm"
|
||||
>
|
||||
<ChevronDownIcon size={14} />
|
||||
</Button>
|
||||
|
|
@ -203,31 +207,34 @@ export function TopBar({
|
|||
</DropdownItem>
|
||||
</DropdownMenu>
|
||||
</Dropdown>
|
||||
</div>
|
||||
|
||||
{/* Moved draft/live labels and download button here */}
|
||||
<div className="flex items-center gap-2 ml-2">
|
||||
{publishing && <Spinner size="sm" />}
|
||||
{isLive && <div className="bg-green-100 dark:bg-green-900/30 text-green-700 dark:text-green-400 px-2 py-1 rounded-md text-xs font-medium flex items-center gap-1.5">
|
||||
<RadioIcon size={16} />
|
||||
Live workflow
|
||||
</div>}
|
||||
{!isLive && <div className="bg-yellow-50 dark:bg-yellow-900/20 text-yellow-600 dark:text-yellow-400 px-2 py-1 rounded-md text-xs font-medium flex items-center gap-1.5">
|
||||
<PenLine size={16} />
|
||||
Draft workflow
|
||||
</div>}
|
||||
<Tooltip content="Download Assistant JSON">
|
||||
<button
|
||||
onClick={onDownloadJSON}
|
||||
className="p-1.5 text-indigo-600 hover:text-indigo-700 dark:text-indigo-400 dark:hover:text-indigo-300 transition-colors"
|
||||
aria-label="Download JSON"
|
||||
type="button"
|
||||
>
|
||||
<DownloadIcon size={20} />
|
||||
</button>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{isLive && <div className="flex items-center gap-2">
|
||||
<Button
|
||||
variant="solid"
|
||||
size="md"
|
||||
onPress={() => onChangeMode('draft')}
|
||||
className="gap-2 px-4 bg-gray-600 hover:bg-gray-700 text-white font-semibold text-sm"
|
||||
startContent={<PenLine size={16} />}
|
||||
>
|
||||
Switch to draft
|
||||
</Button>
|
||||
</div>}
|
||||
|
||||
{!isLive && <Button
|
||||
variant="solid"
|
||||
size="md"
|
||||
onPress={onToggleCopilot}
|
||||
className="gap-2 px-4 bg-indigo-600 hover:bg-indigo-700 text-white font-semibold text-sm"
|
||||
startContent={showCopilot ? null : <span className="text-indigo-300">✨</span>}
|
||||
>
|
||||
{showCopilot ? "Hide Skipper" : "Skipper"}
|
||||
</Button>}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1175,7 +1175,7 @@ export const EntityList = forwardRef<
|
|||
tourTarget="entity-prompts"
|
||||
className={clsx(
|
||||
"h-full",
|
||||
!expandedPanels.prompts && "h-[53px]!"
|
||||
!expandedPanels.prompts && "h-[61px]!"
|
||||
)}
|
||||
title={
|
||||
<div className={`${headerClasses} rounded-md transition-colors h-full`}>
|
||||
|
|
@ -1208,7 +1208,7 @@ export const EntityList = forwardRef<
|
|||
}
|
||||
>
|
||||
{expandedPanels.prompts && (
|
||||
<div className="h-[calc(100%-53px)] overflow-y-auto">
|
||||
<div className="h-[calc(100%-61px)] overflow-y-auto">
|
||||
<div className="p-2">
|
||||
{prompts.length > 0 ? (
|
||||
<div className="space-y-1">
|
||||
|
|
@ -2116,4 +2116,4 @@ function AddVariableModal({ isOpen, onClose, onConfirm, initialName, initialValu
|
|||
</ModalContent>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -965,8 +965,7 @@ export function WorkflowEditor({
|
|||
const saveQueue = useRef<z.infer<typeof Workflow>[]>([]);
|
||||
const saving = useRef(false);
|
||||
const [showCopySuccess, setShowCopySuccess] = useState(false);
|
||||
const [showCopilot, setShowCopilot] = useState(true);
|
||||
const [copilotWidth, setCopilotWidth] = useState<number>(PANEL_RATIOS.copilot);
|
||||
const [activePanel, setActivePanel] = useState<'playground' | 'copilot'>('copilot');
|
||||
const [isInitialState, setIsInitialState] = useState(true);
|
||||
const [showTour, setShowTour] = useState(true);
|
||||
const copilotRef = useRef<{ handleUserMessage: (message: string) => void }>(null);
|
||||
|
|
@ -1010,7 +1009,7 @@ export function WorkflowEditor({
|
|||
|
||||
// Function to trigger copilot chat
|
||||
const triggerCopilotChat = useCallback((message: string) => {
|
||||
setShowCopilot(true);
|
||||
setActivePanel('copilot');
|
||||
// Small delay to ensure copilot is mounted
|
||||
setTimeout(() => {
|
||||
copilotRef.current?.handleUserMessage(message);
|
||||
|
|
@ -1028,14 +1027,14 @@ export function WorkflowEditor({
|
|||
const prompt = localStorage.getItem(`project_prompt_${projectId}`);
|
||||
console.log('init project prompt', prompt);
|
||||
if (prompt) {
|
||||
setShowCopilot(true);
|
||||
setActivePanel('copilot');
|
||||
}
|
||||
}, [projectId]);
|
||||
|
||||
// Hide copilot when switching to live mode
|
||||
// Switch to playground when switching to live mode
|
||||
useEffect(() => {
|
||||
if (isLive) {
|
||||
setShowCopilot(false);
|
||||
setActivePanel('playground');
|
||||
}
|
||||
}, [isLive]);
|
||||
|
||||
|
|
@ -1397,14 +1396,14 @@ export function WorkflowEditor({
|
|||
showCopySuccess={showCopySuccess}
|
||||
canUndo={state.currentIndex > 0}
|
||||
canRedo={state.currentIndex < state.patches.length}
|
||||
showCopilot={showCopilot}
|
||||
activePanel={activePanel}
|
||||
onUndo={() => dispatch({ type: "undo" })}
|
||||
onRedo={() => dispatch({ type: "redo" })}
|
||||
onDownloadJSON={handleDownloadJSON}
|
||||
onPublishWorkflow={handlePublishWorkflow}
|
||||
onChangeMode={onChangeMode}
|
||||
onRevertToLive={handleRevertToLive}
|
||||
onToggleCopilot={() => setShowCopilot(!showCopilot)}
|
||||
onTogglePanel={() => setActivePanel(activePanel === 'playground' ? 'copilot' : 'playground')}
|
||||
/>
|
||||
|
||||
{/* Content Area */}
|
||||
|
|
@ -1465,19 +1464,48 @@ export function WorkflowEditor({
|
|||
<ResizableHandle withHandle className="w-[3px] bg-transparent" />
|
||||
<ResizablePanel
|
||||
minSize={20}
|
||||
defaultSize={showCopilot ? PANEL_RATIOS.chatApp : PANEL_RATIOS.chatApp + PANEL_RATIOS.copilot}
|
||||
defaultSize={PANEL_RATIOS.chatApp + PANEL_RATIOS.copilot}
|
||||
className="overflow-auto"
|
||||
>
|
||||
<ChatApp
|
||||
key={'' + state.present.chatKey}
|
||||
hidden={state.present.selection !== null}
|
||||
projectId={projectId}
|
||||
workflow={state.present.workflow}
|
||||
messageSubscriber={updateChatMessages}
|
||||
onPanelClick={handlePlaygroundClick}
|
||||
triggerCopilotChat={triggerCopilotChat}
|
||||
isLiveWorkflow={isLive}
|
||||
/>
|
||||
<div className={(activePanel === 'playground' && state.present.selection === null) ? 'block h-full' : 'hidden h-full'}>
|
||||
<ChatApp
|
||||
key={'' + state.present.chatKey}
|
||||
hidden={state.present.selection !== null}
|
||||
projectId={projectId}
|
||||
workflow={state.present.workflow}
|
||||
messageSubscriber={updateChatMessages}
|
||||
onPanelClick={handlePlaygroundClick}
|
||||
triggerCopilotChat={triggerCopilotChat}
|
||||
isLiveWorkflow={isLive}
|
||||
activePanel={activePanel}
|
||||
onTogglePanel={() => setActivePanel(activePanel === 'playground' ? 'copilot' : 'playground')}
|
||||
/>
|
||||
</div>
|
||||
<div className={(activePanel === 'copilot' && state.present.selection === null) ? 'block h-full' : 'hidden h-full'}>
|
||||
<Copilot
|
||||
ref={copilotRef}
|
||||
projectId={projectId}
|
||||
workflow={state.present.workflow}
|
||||
dispatch={dispatch}
|
||||
chatContext={
|
||||
state.present.selection &&
|
||||
(state.present.selection.type === "agent" ||
|
||||
state.present.selection.type === "tool" ||
|
||||
state.present.selection.type === "prompt")
|
||||
? {
|
||||
type: state.present.selection.type,
|
||||
name: state.present.selection.name
|
||||
}
|
||||
: chatMessages.length > 0
|
||||
? { type: 'chat', messages: chatMessages }
|
||||
: undefined
|
||||
}
|
||||
isInitialState={isInitialState}
|
||||
dataSources={dataSources}
|
||||
activePanel={activePanel}
|
||||
onTogglePanel={() => setActivePanel(activePanel === 'playground' ? 'copilot' : 'playground')}
|
||||
/>
|
||||
</div>
|
||||
{state.present.selection?.type === "agent" && <AgentConfig
|
||||
key={`agent-${state.present.workflow.agents.findIndex(agent => agent.name === state.present.selection!.name)}`}
|
||||
projectId={projectId}
|
||||
|
|
@ -1563,38 +1591,6 @@ export function WorkflowEditor({
|
|||
</Panel>
|
||||
)}
|
||||
</ResizablePanel>
|
||||
{showCopilot && (
|
||||
<>
|
||||
<ResizableHandle withHandle className="w-[3px] bg-transparent" />
|
||||
<ResizablePanel
|
||||
minSize={10}
|
||||
defaultSize={PANEL_RATIOS.copilot}
|
||||
onResize={(size) => setCopilotWidth(size)}
|
||||
>
|
||||
<Copilot
|
||||
ref={copilotRef}
|
||||
projectId={projectId}
|
||||
workflow={state.present.workflow}
|
||||
dispatch={dispatch}
|
||||
chatContext={
|
||||
state.present.selection &&
|
||||
(state.present.selection.type === "agent" ||
|
||||
state.present.selection.type === "tool" ||
|
||||
state.present.selection.type === "prompt")
|
||||
? {
|
||||
type: state.present.selection.type,
|
||||
name: state.present.selection.name
|
||||
}
|
||||
: chatMessages.length > 0
|
||||
? { type: 'chat', messages: chatMessages }
|
||||
: undefined
|
||||
}
|
||||
isInitialState={isInitialState}
|
||||
dataSources={dataSources}
|
||||
/>
|
||||
</ResizablePanel>
|
||||
</>
|
||||
)}
|
||||
</ResizablePanelGroup>
|
||||
{USE_PRODUCT_TOUR && showTour && (
|
||||
<ProductTour
|
||||
|
|
|
|||
|
|
@ -85,11 +85,11 @@ export function ComposeBoxCopilot({
|
|||
group-hover:opacity-100 transition-opacity">
|
||||
Press ⌘ + Enter to send
|
||||
</div>
|
||||
{/* Outer container with padding */}
|
||||
<div className="rounded-2xl border-[1.5px] border-gray-200 dark:border-[#2a2d31] p-3 relative
|
||||
{/* Outer container without external padding; textarea grows to fill */}
|
||||
<div className="rounded-2xl border-[1.5px] border-gray-200 dark:border-[#2a2d31] relative
|
||||
bg-white dark:bg-[#1e2023] flex items-end gap-2">
|
||||
{/* Textarea */}
|
||||
<div className="flex-1">
|
||||
<div className="flex-1 p-3">
|
||||
<Textarea
|
||||
ref={textareaRef}
|
||||
value={input}
|
||||
|
|
|
|||
|
|
@ -83,12 +83,15 @@ export function Panel({
|
|||
>
|
||||
<div
|
||||
className={clsx(
|
||||
"shrink-0 border-b relative",
|
||||
variant === 'copilot' ? "border-zinc-300 dark:border-zinc-700" : "border-zinc-100 dark:border-zinc-800",
|
||||
// For copilot and playground, mimic TopBar appearance
|
||||
(variant === 'copilot' || variant === 'playground')
|
||||
? "shrink-0 relative rounded-xl bg-white/70 dark:bg-zinc-800/70 shadow-sm backdrop-blur-sm border border-zinc-200 dark:border-zinc-800 px-0 pt-0 pb-2 mx-0 mt-0 mb-2 flex items-center justify-between"
|
||||
: "shrink-0 border-b relative",
|
||||
(variant !== 'copilot' && variant !== 'playground') && "border-zinc-100 dark:border-zinc-800",
|
||||
{
|
||||
"flex flex-col gap-3 px-4 py-3": variant === 'projects',
|
||||
"flex items-center justify-between h-[53px] p-3": isEntityList,
|
||||
"flex items-center justify-between px-6 py-3": !isEntityList && variant !== 'projects'
|
||||
"flex items-center justify-between px-6 py-3": !isEntityList && variant !== 'projects' && variant !== 'copilot' && variant !== 'playground'
|
||||
}
|
||||
)}
|
||||
>
|
||||
|
|
@ -102,39 +105,27 @@ export function Panel({
|
|||
</div>}
|
||||
</>
|
||||
) : variant === 'copilot' ? (
|
||||
<>
|
||||
<div className="w-full flex items-center justify-between px-3 pt-2">
|
||||
<div className="flex items-center gap-2">
|
||||
{icon && icon}
|
||||
<div className="flex flex-col">
|
||||
<div className="font-semibold text-zinc-700 dark:text-zinc-300">
|
||||
{title}
|
||||
</div>
|
||||
{subtitle && (
|
||||
<div className="text-xs text-zinc-500 dark:text-zinc-400">
|
||||
{subtitle}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{rightActions}
|
||||
</>
|
||||
</div>
|
||||
) : variant === 'playground' ? (
|
||||
<>
|
||||
<div className="w-full flex items-center justify-between px-3 pt-2">
|
||||
<div className="flex items-center gap-2">
|
||||
{icon && icon}
|
||||
<div className="flex flex-col">
|
||||
<div className="font-semibold text-zinc-700 dark:text-zinc-300">
|
||||
{title}
|
||||
</div>
|
||||
{subtitle && (
|
||||
<div className="text-xs text-zinc-500 dark:text-zinc-400">
|
||||
{subtitle}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{rightActions}
|
||||
</>
|
||||
</div>
|
||||
) : isEntityList ? (
|
||||
<div className="flex items-center justify-between w-full">
|
||||
{title}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue