diff --git a/apps/rowboat/app/projects/[projectId]/workflow/app.tsx b/apps/rowboat/app/projects/[projectId]/workflow/app.tsx index ab719c3f..9d7a4c8b 100644 --- a/apps/rowboat/app/projects/[projectId]/workflow/app.tsx +++ b/apps/rowboat/app/projects/[projectId]/workflow/app.tsx @@ -37,16 +37,32 @@ export function App({ const stored = window.localStorage.getItem(`workflow_mode_${initialProjectData.id}`); return stored === 'live' || stored === 'draft' ? stored : 'draft'; }); + const [autoPublishEnabled, setAutoPublishEnabled] = useState(() => { + if (typeof window === 'undefined') return true; // Default to auto-publish + const stored = window.localStorage.getItem(`auto_publish_${initialProjectData.id}`); + return stored !== null ? stored === 'true' : true; + }); const [project, setProject] = useState>(initialProjectData); const [dataSources, setDataSources] = useState[]>(initialDataSources); const [loading, setLoading] = useState(false); console.log('workflow app.tsx render'); + const handleToggleAutoPublish = (enabled: boolean) => { + setAutoPublishEnabled(enabled); + if (typeof window !== 'undefined') { + window.localStorage.setItem(`auto_publish_${initialProjectData.id}`, enabled.toString()); + } + }; + // choose which workflow to display - let workflow: z.infer | undefined = project?.draftWorkflow; - if (mode == 'live') { - workflow = project?.liveWorkflow; + let workflow: z.infer | undefined; + if (autoPublishEnabled) { + // In auto-publish mode, always use draft (since they're synced) + workflow = project?.draftWorkflow; + } else { + // Manual mode: use current logic + workflow = mode === 'live' ? project?.liveWorkflow : project?.draftWorkflow; } const reloadData = useCallback(async () => { @@ -132,6 +148,8 @@ export function App({ {!loading && project && workflow && (dataSources !== null) && Promise; publishing: boolean; isLive: boolean; + autoPublishEnabled: boolean; + onToggleAutoPublish: (enabled: boolean) => void; showCopySuccess: boolean; showBuildModeBanner: boolean; canUndo: boolean; @@ -50,6 +52,8 @@ export function TopBar({ onProjectNameCommit, publishing, isLive, + autoPublishEnabled, + onToggleAutoPublish, showCopySuccess, showBuildModeBanner, canUndo, @@ -82,6 +86,15 @@ export function TopBar({ const router = useRouter(); const params = useParams(); const projectId = typeof (params as any).projectId === 'string' ? (params as any).projectId : (params as any).projectId?.[0]; + + // Share modal state + const { isOpen: isShareModalOpen, onOpen: onShareModalOpen, onClose: onShareModalClose } = useDisclosure(); + + const handleShareClick = () => { + onShareWorkflow(); // Call the original share function to generate URL + onShareModalOpen(); // Open the modal + }; + // Progress bar steps with completion logic and current step detection const step1Complete = hasAgentInstructionChanges; const step2Complete = hasPlaygroundTested && hasAgentInstructionChanges; @@ -99,9 +112,10 @@ export function TopBar({ ]; return ( + <>
-
+
{/* Project Name Editor */}
- {/* Show divider and mode indicator */} - {isLive &&
} - {isLive ? ( + {/* Mode pill and auto-publish checkbox */} +
+ + {/* Mode pill */} +
+ + + {autoPublishEnabled ? 'Live ' : (isLive ? 'Live ' : 'Draft')} + +
+ + {/* Auto-publish checkbox or Switch to draft button */} + {!autoPublishEnabled && isLive ? (
@@ -274,10 +305,11 @@ export function TopBar({ })()}
)} - {/* Deploy CTA - always visible */} + {/* Deploy CTA - conditional based on auto-publish mode */}
- {isLive ? ( + {autoPublishEnabled ? ( <> + {/* Auto-publish mode: Show Use Assistant button */} + + + + + + } + onPress={onDownloadJSON} + > + Download JSON + + +
- - - - {shareUrl && ( - - - - )} - - -
) : ( - <> -
- {(!hasAgents) ? ( - - - - - - ) : ( - - )} - {hasAgents ? ( + // Manual publish mode: Show current publish/live logic + isLive ? ( + <> - + } - onPress={() => onChangeMode('live')} + key="chat" + startContent={} + onPress={() => { + onUseAssistantClick(); + onStartNewChatAndFocus(); + }} > - View live version + Chat with Assistant } - onPress={onRevertToLive} - className="text-red-600 dark:text-red-400" + key="api-sdk" + startContent={} + onPress={() => { + onUseAssistantClick(); + if (projectId) { router.push(`/projects/${projectId}/config`); } + }} > - Reset to live version + API & SDK Settings + + } + onPress={() => { + onUseAssistantClick(); + if (projectId) { router.push(`/projects/${projectId}/manage-triggers`); } + }} + > + Manage Triggers - ) : ( - - + +
+ {publishing && } +
- - - )} -
- -
- {publishing && } - {isLive &&
- - Live workflow -
} - {!isLive &&
- - Draft workflow -
} - - + + + } + onPress={onDownloadJSON} + > + Download JSON + + + +
+
+ ) : ( + // Draft mode in manual publish: Show publish button + <> +
+ {(!hasAgents) ? ( + + + + + + ) : ( + - - {shareUrl && ( - - + Publish + + )} + {hasAgents ? ( + + + + + + } + onPress={() => onChangeMode('live')} + > + View live version + + } + onPress={onRevertToLive} + className="text-red-600 dark:text-red-400" + > + Reset to live version + + + + ) : ( + + + + )} - - - -
- +
+ +
+ {publishing && } +
+ + + + + + + } + onPress={onDownloadJSON} + > + Download JSON + + + +
+
+ + ) )}
+ + {/* Share Modal */} + + + + Share Assistant + + +
+

+ Share this assistant with others using the URL below: +

+ {shareUrl ? ( +
+ + +
+ ) : ( +
+ + + Generating share URL... + +
+ )} +
+
+ + + +
+
+ ); } diff --git a/apps/rowboat/app/projects/[projectId]/workflow/workflow_editor.tsx b/apps/rowboat/app/projects/[projectId]/workflow/workflow_editor.tsx index ccfaed3b..526694cb 100644 --- a/apps/rowboat/app/projects/[projectId]/workflow/workflow_editor.tsx +++ b/apps/rowboat/app/projects/[projectId]/workflow/workflow_editor.tsx @@ -960,6 +960,8 @@ export function WorkflowEditor({ projectConfig, eligibleModels, isLive, + autoPublishEnabled, + onToggleAutoPublish, onChangeMode, onRevertToLive, onProjectToolsUpdated, @@ -978,6 +980,8 @@ export function WorkflowEditor({ projectConfig: z.infer; eligibleModels: z.infer | "*"; isLive: boolean; + autoPublishEnabled: boolean; + onToggleAutoPublish: (enabled: boolean) => void; onChangeMode: (mode: 'draft' | 'live') => void; onRevertToLive: () => void; onProjectToolsUpdated?: () => void; @@ -1604,10 +1608,17 @@ export function WorkflowEditor({ saveQueue.current = []; try { - if (isLive) { - return; - } else { + if (autoPublishEnabled) { + // Auto-publish mode: save to both draft and live await saveWorkflow(projectId, workflowToSave); + await publishWorkflow(projectId, workflowToSave); + } else { + // Manual mode: current logic + if (isLive) { + return; + } else { + await saveWorkflow(projectId, workflowToSave); + } } } finally { saving.current = false; @@ -1617,7 +1628,7 @@ export function WorkflowEditor({ dispatch({ type: "set_saving", saving: false }); } } - }, [isLive, projectId]); + }, [autoPublishEnabled, isLive, projectId]); useEffect(() => { if (state.present.pendingChanges && state.present.workflow) { @@ -1863,6 +1874,8 @@ export function WorkflowEditor({ onProjectNameCommit={handleProjectNameCommit} publishing={state.present.publishing} isLive={isLive} + autoPublishEnabled={autoPublishEnabled} + onToggleAutoPublish={onToggleAutoPublish} showCopySuccess={showCopySuccess} showBuildModeBanner={showBuildModeBanner} canUndo={state.currentIndex > 0}