mirror of
https://github.com/rowboatlabs/rowboat.git
synced 2026-05-05 13:22:38 +02:00
Progressbar (#231)
* added basic progress bar * step 1 turns green when any agent instructio is changed * step 2 is done after playground chat * step 3 turns green on publish * step 4 turns green on use assistant * step 1 turns green on copilot changes too * reduced font size of the live workflow warning * better hover texts for steps * change progress bar style * better tool tips * reverted styling of use assistant button * chat with assistant option collapses the left pane * remove hide left panel button * made progress bar hover text more prominent * add labels to progress bar * added tour for build * added tour for test * added tour for publish * added tour for use step * added tool tip for each step to click for tour * refined wording in product tours * added jobs and conversations to the product tour
This commit is contained in:
parent
c793f0a344
commit
d899966107
7 changed files with 449 additions and 38 deletions
|
|
@ -19,6 +19,7 @@ export function App({
|
|||
isLiveWorkflow,
|
||||
activePanel,
|
||||
onTogglePanel,
|
||||
onMessageSent,
|
||||
}: {
|
||||
hidden?: boolean;
|
||||
projectId: string;
|
||||
|
|
@ -29,6 +30,7 @@ export function App({
|
|||
isLiveWorkflow: boolean;
|
||||
activePanel: 'playground' | 'copilot';
|
||||
onTogglePanel: () => void;
|
||||
onMessageSent?: () => void;
|
||||
}) {
|
||||
const [counter, setCounter] = useState<number>(0);
|
||||
const [showDebugMessages, setShowDebugMessages] = useState<boolean>(true);
|
||||
|
|
@ -142,6 +144,7 @@ export function App({
|
|||
showDebugMessages={showDebugMessages}
|
||||
triggerCopilotChat={triggerCopilotChat}
|
||||
isLiveWorkflow={isLiveWorkflow}
|
||||
onMessageSent={onMessageSent}
|
||||
/>
|
||||
</div>
|
||||
</Panel>
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ export function Chat({
|
|||
showJsonMode = false,
|
||||
triggerCopilotChat,
|
||||
isLiveWorkflow,
|
||||
onMessageSent,
|
||||
}: {
|
||||
projectId: string;
|
||||
workflow: z.infer<typeof Workflow>;
|
||||
|
|
@ -31,6 +32,7 @@ export function Chat({
|
|||
showJsonMode?: boolean;
|
||||
triggerCopilotChat?: (message: string) => void;
|
||||
isLiveWorkflow: boolean;
|
||||
onMessageSent?: () => void;
|
||||
}) {
|
||||
const conversationId = useRef<string | null>(null);
|
||||
const [messages, setMessages] = useState<z.infer<typeof Message>[]>([]);
|
||||
|
|
@ -158,6 +160,11 @@ export function Chat({
|
|||
setMessages(updatedMessages);
|
||||
setError(null);
|
||||
setIsLastInteracted(true);
|
||||
|
||||
// Mark playground as tested when user sends a message
|
||||
if (onMessageSent) {
|
||||
onMessageSent();
|
||||
}
|
||||
}
|
||||
|
||||
// clean up event source on component unmount
|
||||
|
|
|
|||
|
|
@ -2,8 +2,9 @@
|
|||
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 { RadioIcon, RedoIcon, UndoIcon, RocketIcon, PenLine, AlertTriangle, DownloadIcon, SettingsIcon, ChevronDownIcon, ZapIcon, Clock, Plug, MessageCircleIcon } from "lucide-react";
|
||||
import { useParams, useRouter } from "next/navigation";
|
||||
import { ProgressBar, ProgressStep } from "@/components/ui/progress-bar";
|
||||
|
||||
interface TopBarProps {
|
||||
localProjectName: string;
|
||||
|
|
@ -17,6 +18,10 @@ interface TopBarProps {
|
|||
canUndo: boolean;
|
||||
canRedo: boolean;
|
||||
activePanel: 'playground' | 'copilot';
|
||||
hasAgentInstructionChanges: boolean;
|
||||
hasPlaygroundTested: boolean;
|
||||
hasPublished: boolean;
|
||||
hasClickedUse: boolean;
|
||||
onUndo: () => void;
|
||||
onRedo: () => void;
|
||||
onDownloadJSON: () => void;
|
||||
|
|
@ -24,6 +29,12 @@ interface TopBarProps {
|
|||
onChangeMode: (mode: 'draft' | 'live') => void;
|
||||
onRevertToLive: () => void;
|
||||
onTogglePanel: () => void;
|
||||
onUseAssistantClick: () => void;
|
||||
onStartNewChatAndFocus: () => void;
|
||||
onStartBuildTour?: () => void;
|
||||
onStartTestTour?: () => void;
|
||||
onStartPublishTour?: () => void;
|
||||
onStartUseTour?: () => void;
|
||||
}
|
||||
|
||||
export function TopBar({
|
||||
|
|
@ -38,6 +49,10 @@ export function TopBar({
|
|||
canUndo,
|
||||
canRedo,
|
||||
activePanel,
|
||||
hasAgentInstructionChanges,
|
||||
hasPlaygroundTested,
|
||||
hasPublished,
|
||||
hasClickedUse,
|
||||
onUndo,
|
||||
onRedo,
|
||||
onDownloadJSON,
|
||||
|
|
@ -45,10 +60,32 @@ export function TopBar({
|
|||
onChangeMode,
|
||||
onRevertToLive,
|
||||
onTogglePanel,
|
||||
onUseAssistantClick,
|
||||
onStartNewChatAndFocus,
|
||||
onStartBuildTour,
|
||||
onStartTestTour,
|
||||
onStartPublishTour,
|
||||
onStartUseTour,
|
||||
}: TopBarProps) {
|
||||
const router = useRouter();
|
||||
const params = useParams();
|
||||
const projectId = typeof (params as any).projectId === 'string' ? (params as any).projectId : (params as any).projectId?.[0];
|
||||
// Progress bar steps with completion logic and current step detection
|
||||
const step1Complete = hasAgentInstructionChanges;
|
||||
const step2Complete = hasPlaygroundTested && hasAgentInstructionChanges;
|
||||
const step3Complete = hasPublished && hasPlaygroundTested && hasAgentInstructionChanges;
|
||||
const step4Complete = hasClickedUse && hasPublished && hasPlaygroundTested && hasAgentInstructionChanges;
|
||||
|
||||
// Determine current step (first incomplete step)
|
||||
const currentStep = !step1Complete ? 1 : !step2Complete ? 2 : !step3Complete ? 3 : !step4Complete ? 4 : null;
|
||||
|
||||
const progressSteps: ProgressStep[] = [
|
||||
{ id: 1, label: "Build: Ask the copilot to create your assistant. Add tools and connect data sources.", completed: step1Complete, isCurrent: currentStep === 1 },
|
||||
{ id: 2, label: "Test: Test out your assistant by chatting with it. Use 'Fix' and 'Explain' to improve it.", completed: step2Complete, isCurrent: currentStep === 2 },
|
||||
{ id: 3, label: "Publish: Make it live with the Publish button. You can always switch back to draft.", completed: step3Complete, isCurrent: currentStep === 3 },
|
||||
{ id: 4, label: "Use: Click the 'Use Assistant' button to chat, set triggers (like emails), or connect via API.", completed: step4Complete, isCurrent: currentStep === 4 },
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="rounded-xl bg-white/70 dark:bg-zinc-800/70 shadow-sm backdrop-blur-sm border border-zinc-200 dark:border-zinc-800 px-5 py-2">
|
||||
<div className="flex justify-between items-center">
|
||||
|
|
@ -92,16 +129,33 @@ export function TopBar({
|
|||
</Button>
|
||||
) : null}
|
||||
</div>
|
||||
{showCopySuccess && <div className="flex items-center gap-2">
|
||||
<div className="text-green-500">Copied to clipboard</div>
|
||||
</div>}
|
||||
{showBuildModeBanner && <div className="flex items-center gap-2">
|
||||
<AlertTriangle className="w-4 h-4 text-blue-600 dark:text-blue-400" />
|
||||
<div className="text-blue-700 dark:text-blue-300 text-sm">
|
||||
Switched to draft mode. You can now make changes to your workflow.
|
||||
</div>
|
||||
</div>}
|
||||
|
||||
{/* Progress Bar - Center */}
|
||||
<div className="flex-1 flex justify-center">
|
||||
<ProgressBar
|
||||
steps={progressSteps}
|
||||
onStepClick={(step) => {
|
||||
if (step.id === 1 && onStartBuildTour) onStartBuildTour();
|
||||
if (step.id === 2 && onStartTestTour) onStartTestTour();
|
||||
if (step.id === 3 && onStartPublishTour) onStartPublishTour();
|
||||
if (step.id === 4 && onStartUseTour) onStartUseTour();
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Right side buttons */}
|
||||
<div className="flex items-center gap-2">
|
||||
{showCopySuccess && <div className="flex items-center gap-2 mr-4">
|
||||
<div className="text-green-500">Copied to clipboard</div>
|
||||
</div>}
|
||||
|
||||
{showBuildModeBanner && <div className="flex items-center gap-2 mr-4">
|
||||
<AlertTriangle className="w-4 h-4 text-blue-600 dark:text-blue-400" />
|
||||
<div className="text-blue-700 dark:text-blue-300 text-sm">
|
||||
Switched to draft mode. You can now make changes to your workflow.
|
||||
</div>
|
||||
</div>}
|
||||
|
||||
|
||||
{!isLive && <>
|
||||
<CustomButton
|
||||
|
|
@ -139,24 +193,41 @@ export function TopBar({
|
|||
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} />}
|
||||
onPress={onUseAssistantClick}
|
||||
>
|
||||
Use Assistant
|
||||
<ChevronDownIcon size={14} />
|
||||
</Button>
|
||||
</DropdownTrigger>
|
||||
<DropdownMenu aria-label="Assistant access options">
|
||||
<DropdownItem
|
||||
key="chat"
|
||||
startContent={<MessageCircleIcon size={16} />}
|
||||
onPress={() => {
|
||||
onUseAssistantClick();
|
||||
onStartNewChatAndFocus();
|
||||
}}
|
||||
>
|
||||
Chat with Assistant
|
||||
</DropdownItem>
|
||||
<DropdownItem
|
||||
key="api-sdk"
|
||||
startContent={<SettingsIcon size={16} />}
|
||||
onPress={() => { if (projectId) { router.push(`/projects/${projectId}/config`); } }}
|
||||
onPress={() => {
|
||||
onUseAssistantClick();
|
||||
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`); } }}
|
||||
>
|
||||
onPress={() => {
|
||||
onUseAssistantClick();
|
||||
if (projectId) { router.push(`/projects/${projectId}/manage-triggers`); }
|
||||
}}
|
||||
>
|
||||
Manage Triggers
|
||||
</DropdownItem>
|
||||
</DropdownMenu>
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ interface StateItem {
|
|||
chatKey: number;
|
||||
lastUpdatedAt: string;
|
||||
isLive: boolean;
|
||||
|
||||
agentInstructionsChanged: boolean;
|
||||
}
|
||||
|
||||
interface State {
|
||||
|
|
@ -656,6 +656,10 @@ function reducer(state: State, action: Action): State {
|
|||
break;
|
||||
}
|
||||
case "update_agent": {
|
||||
// Check if instructions are being changed
|
||||
if (action.agent.instructions !== undefined) {
|
||||
draft.agentInstructionsChanged = true;
|
||||
}
|
||||
|
||||
// update agent data
|
||||
draft.workflow.agents = draft.workflow.agents.map((agent) =>
|
||||
|
|
@ -930,7 +934,7 @@ export function WorkflowEditor({
|
|||
chatKey: 0,
|
||||
lastUpdatedAt: workflow.lastUpdatedAt,
|
||||
isLive,
|
||||
|
||||
agentInstructionsChanged: false,
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -944,11 +948,16 @@ export function WorkflowEditor({
|
|||
const [activePanel, setActivePanel] = useState<'playground' | 'copilot'>('copilot');
|
||||
const [isInitialState, setIsInitialState] = useState(true);
|
||||
const [showBuildModeBanner, setShowBuildModeBanner] = useState(false);
|
||||
const [isLeftPanelCollapsed, setIsLeftPanelCollapsed] = useState(false);
|
||||
const [showEditModal, setShowEditModal] = useState(false);
|
||||
const [pendingAction, setPendingAction] = useState<Action | null>(null);
|
||||
const [configKey, setConfigKey] = useState(0);
|
||||
const [lastWorkflowId, setLastWorkflowId] = useState<string | null>(null);
|
||||
const [showTour, setShowTour] = useState(true);
|
||||
const [showBuildTour, setShowBuildTour] = useState(false);
|
||||
const [showTestTour, setShowTestTour] = useState(false);
|
||||
const [showPublishTour, setShowPublishTour] = useState(false);
|
||||
const [showUseTour, setShowUseTour] = useState(false);
|
||||
|
||||
// Centralized mode transition handler
|
||||
const handleModeTransition = useCallback((newMode: 'draft' | 'live', reason: 'publish' | 'view_live' | 'switch_draft' | 'modal_switch') => {
|
||||
|
|
@ -994,6 +1003,71 @@ export function WorkflowEditor({
|
|||
const [projectNameError, setProjectNameError] = useState<string | null>(null);
|
||||
const [isEditingProjectName, setIsEditingProjectName] = useState<boolean>(false);
|
||||
const [pendingProjectName, setPendingProjectName] = useState<string | null>(null);
|
||||
|
||||
// Build progress tracking - persists once set to true
|
||||
const [hasAgentInstructionChanges, setHasAgentInstructionChanges] = useState<boolean>(() => {
|
||||
return localStorage.getItem(`agent_instructions_changed_${projectId}`) === 'true';
|
||||
});
|
||||
|
||||
// Test progress tracking - persists once set to true
|
||||
const [hasPlaygroundTested, setHasPlaygroundTested] = useState<boolean>(() => {
|
||||
return localStorage.getItem(`playground_tested_${projectId}`) === 'true';
|
||||
});
|
||||
|
||||
// Publish progress tracking - persists once set to true
|
||||
const [hasPublished, setHasPublished] = useState<boolean>(() => {
|
||||
return localStorage.getItem(`has_published_${projectId}`) === 'true';
|
||||
});
|
||||
|
||||
// Use progress tracking - persists once set to true
|
||||
const [hasClickedUse, setHasClickedUse] = useState<boolean>(() => {
|
||||
return localStorage.getItem(`has_clicked_use_${projectId}`) === 'true';
|
||||
});
|
||||
|
||||
// Function to mark agent instructions as changed (persists in localStorage)
|
||||
const markAgentInstructionsChanged = useCallback(() => {
|
||||
if (!hasAgentInstructionChanges) {
|
||||
setHasAgentInstructionChanges(true);
|
||||
localStorage.setItem(`agent_instructions_changed_${projectId}`, 'true');
|
||||
}
|
||||
}, [hasAgentInstructionChanges, projectId]);
|
||||
|
||||
// Function to mark playground as tested (persists in localStorage)
|
||||
const markPlaygroundTested = useCallback(() => {
|
||||
if (!hasPlaygroundTested && hasAgentInstructionChanges) { // Only mark if step 1 is complete
|
||||
setHasPlaygroundTested(true);
|
||||
localStorage.setItem(`playground_tested_${projectId}`, 'true');
|
||||
}
|
||||
}, [hasPlaygroundTested, hasAgentInstructionChanges, projectId]);
|
||||
|
||||
// Function to mark as published (persists in localStorage)
|
||||
const markAsPublished = useCallback(() => {
|
||||
if (!hasPublished) {
|
||||
setHasPublished(true);
|
||||
localStorage.setItem(`has_published_${projectId}`, 'true');
|
||||
}
|
||||
}, [hasPublished, projectId]);
|
||||
|
||||
// Function to mark Use Assistant button as clicked (persists in localStorage)
|
||||
const markUseAssistantClicked = useCallback(() => {
|
||||
if (!hasClickedUse) {
|
||||
setHasClickedUse(true);
|
||||
localStorage.setItem(`has_clicked_use_${projectId}`, 'true');
|
||||
}
|
||||
}, [hasClickedUse, projectId]);
|
||||
|
||||
// Reference to start new chat function from playground
|
||||
const startNewChatRef = useRef<(() => void) | null>(null);
|
||||
|
||||
// Function to start new chat and focus
|
||||
const handleStartNewChatAndFocus = useCallback(() => {
|
||||
if (startNewChatRef.current) {
|
||||
startNewChatRef.current();
|
||||
}
|
||||
// Switch to playground (chat) mode and collapse left panel
|
||||
setActivePanel('playground');
|
||||
setIsLeftPanelCollapsed(true);
|
||||
}, []);
|
||||
|
||||
// Load agent order from localStorage on mount
|
||||
// useEffect(() => {
|
||||
|
|
@ -1061,6 +1135,13 @@ export function WorkflowEditor({
|
|||
}
|
||||
}, [state.present.workflow, state.present.pendingChanges]);
|
||||
|
||||
// Track agent instruction changes from copilot
|
||||
useEffect(() => {
|
||||
if (state.present.agentInstructionsChanged) {
|
||||
markAgentInstructionsChanged();
|
||||
}
|
||||
}, [state.present.agentInstructionsChanged, markAgentInstructionsChanged]);
|
||||
|
||||
function handleSelectAgent(name: string) {
|
||||
dispatch({ type: "select_agent", name });
|
||||
}
|
||||
|
|
@ -1158,6 +1239,10 @@ export function WorkflowEditor({
|
|||
}
|
||||
|
||||
function handleUpdateAgent(name: string, agent: Partial<z.infer<typeof WorkflowAgent>>) {
|
||||
// Check if instructions are being changed
|
||||
if (agent.instructions !== undefined) {
|
||||
markAgentInstructionsChanged();
|
||||
}
|
||||
dispatch({ type: "update_agent", name, agent });
|
||||
}
|
||||
|
||||
|
|
@ -1236,6 +1321,7 @@ export function WorkflowEditor({
|
|||
dispatch({ type: 'set_publishing', publishing: true });
|
||||
try {
|
||||
await publishWorkflow(projectId, state.present.workflow);
|
||||
markAsPublished(); // Mark step 3 as completed when user publishes
|
||||
// Use centralized mode transition for publish
|
||||
handleModeTransition('live', 'publish');
|
||||
// reflect live mode both internally and externally in one go
|
||||
|
|
@ -1438,6 +1524,10 @@ export function WorkflowEditor({
|
|||
}
|
||||
}
|
||||
|
||||
function handleToggleLeftPanel() {
|
||||
setIsLeftPanelCollapsed(!isLeftPanelCollapsed);
|
||||
}
|
||||
|
||||
const validateProjectName = (value: string) => {
|
||||
if (value.length === 0) {
|
||||
setProjectNameError("Project name cannot be empty");
|
||||
|
|
@ -1544,6 +1634,10 @@ export function WorkflowEditor({
|
|||
canUndo={state.currentIndex > 0}
|
||||
canRedo={state.currentIndex < state.patches.length}
|
||||
activePanel={activePanel}
|
||||
hasAgentInstructionChanges={hasAgentInstructionChanges}
|
||||
hasPlaygroundTested={hasPlaygroundTested}
|
||||
hasPublished={hasPublished}
|
||||
hasClickedUse={hasClickedUse}
|
||||
onUndo={() => dispatchGuarded({ type: "undo" })}
|
||||
onRedo={() => dispatchGuarded({ type: "redo" })}
|
||||
onDownloadJSON={handleDownloadJSON}
|
||||
|
|
@ -1551,6 +1645,17 @@ export function WorkflowEditor({
|
|||
onChangeMode={onChangeMode}
|
||||
onRevertToLive={handleRevertToLive}
|
||||
onTogglePanel={handleTogglePanel}
|
||||
onUseAssistantClick={markUseAssistantClicked}
|
||||
onStartNewChatAndFocus={handleStartNewChatAndFocus}
|
||||
onStartBuildTour={() => setShowBuildTour(true)}
|
||||
onStartTestTour={() => setShowTestTour(true)}
|
||||
onStartPublishTour={() => {
|
||||
if (isLive) {
|
||||
handleModeTransition('draft', 'switch_draft');
|
||||
}
|
||||
setShowPublishTour(true);
|
||||
}}
|
||||
onStartUseTour={() => setShowUseTour(true)}
|
||||
/>
|
||||
|
||||
{/* Content Area */}
|
||||
|
|
@ -1559,6 +1664,7 @@ export function WorkflowEditor({
|
|||
key={`entity-list-${state.present.selection ? '3-pane' : '2-pane'}`}
|
||||
minSize={10}
|
||||
defaultSize={PANEL_RATIOS.entityList}
|
||||
className={isLeftPanelCollapsed ? 'hidden' : ''}
|
||||
>
|
||||
<div className="flex flex-col h-full">
|
||||
<EntityList
|
||||
|
|
@ -1612,7 +1718,7 @@ export function WorkflowEditor({
|
|||
/>
|
||||
</div>
|
||||
</ResizablePanel>
|
||||
<ResizableHandle withHandle className={`w-[3px] bg-transparent ${!state.present.selection ? 'hidden' : ''}`} />
|
||||
<ResizableHandle withHandle className={`w-[3px] bg-transparent ${(isLeftPanelCollapsed || !state.present.selection) ? 'hidden' : ''}`} />
|
||||
|
||||
{/* Config Panel - always rendered, visibility controlled */}
|
||||
<ResizablePanel
|
||||
|
|
@ -1705,8 +1811,8 @@ export function WorkflowEditor({
|
|||
</Panel>
|
||||
)}
|
||||
</ResizablePanel>
|
||||
{/* Second handle - always show (between config and chat panels) */}
|
||||
<ResizableHandle withHandle className="w-[3px] bg-transparent" />
|
||||
{/* Second handle - between config and chat panels */}
|
||||
<ResizableHandle withHandle className={`w-[3px] bg-transparent ${(isLeftPanelCollapsed && !state.present.selection) ? 'hidden' : ''}`} />
|
||||
|
||||
{/* ChatApp/Copilot Panel - always visible */}
|
||||
<ResizablePanel
|
||||
|
|
@ -1726,6 +1832,7 @@ export function WorkflowEditor({
|
|||
isLiveWorkflow={isLive}
|
||||
activePanel={activePanel}
|
||||
onTogglePanel={handleTogglePanel}
|
||||
onMessageSent={markPlaygroundTested}
|
||||
/>
|
||||
</div>
|
||||
<div className={(activePanel === 'copilot') ? 'block h-full' : 'hidden h-full'}>
|
||||
|
|
@ -1761,6 +1868,65 @@ export function WorkflowEditor({
|
|||
onComplete={() => setShowTour(false)}
|
||||
/>
|
||||
)}
|
||||
{showBuildTour && (
|
||||
<ProductTour
|
||||
projectId={projectId}
|
||||
forceStart
|
||||
stepsOverride={[
|
||||
{ target: 'copilot', title: 'Step 1/5', content: 'Use Copilot to create and refine agents. Describe what you need, then iterate with its suggestions.' },
|
||||
{ target: 'entity-agents', title: 'Step 2/5', content: 'All your agents appear here. Adjust instructions, switch models, and fine-tune their behavior.' },
|
||||
{ target: 'entity-tools', title: 'Step 3/5', content: 'Pick from thousands of ready-made tools or connect your own MCP servers.' },
|
||||
{ target: 'entity-data', title: 'Step 4/5', content: 'Upload files, scrape websites, or add free-text knowledge to guide your agents.' },
|
||||
{ target: 'entity-prompts', title: 'Step 5/5', content: 'Define reusable context variables automatically shared across all agents.' },
|
||||
]}
|
||||
onStepChange={(_, step) => {
|
||||
if (step.target === 'copilot') setActivePanel('copilot');
|
||||
}}
|
||||
onComplete={() => setShowBuildTour(false)}
|
||||
/>
|
||||
)}
|
||||
{showTestTour && (
|
||||
<ProductTour
|
||||
projectId={projectId}
|
||||
forceStart
|
||||
stepsOverride={[
|
||||
{ target: 'playground', title: 'Step 1/2', content: 'Chat with your assistant to test it. Send messages, watch tool calls in action, and debug agent flows.' },
|
||||
{ target: 'copilot', title: 'Step 2/2', content: 'Ask Copilot to improve your agents based on test results. Use “Fix” and “Explain” to iterate quickly.' },
|
||||
]}
|
||||
onStepChange={(index) => {
|
||||
if (index === 0) setActivePanel('playground');
|
||||
if (index === 1) setActivePanel('copilot');
|
||||
}}
|
||||
onComplete={() => setShowTestTour(false)}
|
||||
/>
|
||||
)}
|
||||
{showUseTour && (
|
||||
<ProductTour
|
||||
projectId={projectId}
|
||||
forceStart
|
||||
stepsOverride={[
|
||||
{ target: 'playground', title: 'Step 1/5', content: 'Chat: you can chat with your assistant here.' },
|
||||
{ target: 'triggers', title: 'Step 2/5', content: 'Triggers: set up external (webhook/integration) or time-based schedules.' },
|
||||
{ target: 'jobs', title: 'Step 3/5', content: 'Jobs: monitor your trigger runs and scheduled tasks here.' },
|
||||
{ target: 'settings', title: 'Step 4/5', content: 'Settings: find API keys to connect with the API and SDK.' },
|
||||
{ target: 'conversations', title: 'Step 5/5', content: 'Conversations: see all past interactions in one place, including manual chats, trigger activity, and API calls.' },
|
||||
]}
|
||||
onStepChange={(index) => {
|
||||
if (index === 0) setActivePanel('playground');
|
||||
}}
|
||||
onComplete={() => setShowUseTour(false)}
|
||||
/>
|
||||
)}
|
||||
{showPublishTour && (
|
||||
<ProductTour
|
||||
projectId={projectId}
|
||||
forceStart
|
||||
stepsOverride={[
|
||||
{ target: 'deploy', title: 'Publish', content: 'Click Publish to make your workflow live, enabling triggers and API/SDK access. You can revert to a draft at any time.' },
|
||||
]}
|
||||
onComplete={() => setShowPublishTour(false)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Revert to Live Confirmation Modal */}
|
||||
<Modal isOpen={isRevertModalOpen} onClose={onRevertModalClose}>
|
||||
|
|
|
|||
|
|
@ -193,7 +193,19 @@ export default function Sidebar({ projectId, useAuth, collapsed = false, onToggl
|
|||
: 'text-zinc-600 dark:text-zinc-400 hover:bg-zinc-100 dark:hover:bg-zinc-800/50 hover:text-zinc-900 dark:hover:text-zinc-300'
|
||||
}
|
||||
`}
|
||||
data-tour-target={item.href === 'config' ? 'settings' : item.href === 'sources' ? 'entity-data-sources' : undefined}
|
||||
data-tour-target={
|
||||
item.href === 'config'
|
||||
? 'settings'
|
||||
: item.href === 'sources'
|
||||
? 'entity-data-sources'
|
||||
: item.href === 'manage-triggers'
|
||||
? 'triggers'
|
||||
: item.href === 'jobs'
|
||||
? 'jobs'
|
||||
: item.href === 'conversations'
|
||||
? 'conversations'
|
||||
: undefined
|
||||
}
|
||||
>
|
||||
<Icon
|
||||
size={COLLAPSED_ICON_SIZE}
|
||||
|
|
@ -218,7 +230,19 @@ export default function Sidebar({ projectId, useAuth, collapsed = false, onToggl
|
|||
: 'text-zinc-600 dark:text-zinc-400 hover:bg-zinc-100 dark:hover:bg-zinc-800/50 hover:text-zinc-900 dark:hover:text-zinc-300'
|
||||
}
|
||||
`}
|
||||
data-tour-target={item.href === 'config' ? 'settings' : item.href === 'sources' ? 'entity-data-sources' : undefined}
|
||||
data-tour-target={
|
||||
item.href === 'config'
|
||||
? 'settings'
|
||||
: item.href === 'sources'
|
||||
? 'entity-data-sources'
|
||||
: item.href === 'manage-triggers'
|
||||
? 'triggers'
|
||||
: item.href === 'jobs'
|
||||
? 'jobs'
|
||||
: item.href === 'conversations'
|
||||
? 'conversations'
|
||||
: undefined
|
||||
}
|
||||
>
|
||||
<Icon
|
||||
size={EXPANDED_ICON_SIZE}
|
||||
|
|
@ -375,4 +399,4 @@ export default function Sidebar({ projectId, useAuth, collapsed = false, onToggl
|
|||
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue