diff --git a/apps/rowboat/app/projects/[projectId]/manage-triggers/components/create-recurring-job-rule-form.tsx b/apps/rowboat/app/projects/[projectId]/manage-triggers/components/create-recurring-job-rule-form.tsx index ccdd3dee..d6a12dee 100644 --- a/apps/rowboat/app/projects/[projectId]/manage-triggers/components/create-recurring-job-rule-form.tsx +++ b/apps/rowboat/app/projects/[projectId]/manage-triggers/components/create-recurring-job-rule-form.tsx @@ -25,7 +25,15 @@ const commonCronExamples = [ { label: "Monthly on the 1st at midnight", value: "0 0 1 * *" }, ]; -export function CreateRecurringJobRuleForm({ projectId }: { projectId: string }) { +export function CreateRecurringJobRuleForm({ + projectId, + onBack, + hasExistingTriggers = true +}: { + projectId: string; + onBack?: () => void; + hasExistingTriggers?: boolean; +}) { const router = useRouter(); const [loading, setLoading] = useState(false); const [messages, setMessages] = useState([ @@ -89,7 +97,11 @@ export function CreateRecurringJobRuleForm({ projectId }: { projectId: string }) input: { messages: convertedMessages }, cron: cronExpression, }); - router.push(`/projects/${projectId}/manage-triggers?tab=recurring`); + if (onBack) { + onBack(); + } else { + router.push(`/projects/${projectId}/manage-triggers?tab=recurring`); + } } catch (error) { console.error("Failed to create recurring job rule:", error); alert("Failed to create recurring job rule"); @@ -102,11 +114,23 @@ export function CreateRecurringJobRuleForm({ projectId }: { projectId: string }) - - - + ) : hasExistingTriggers ? ( + + + + ) : null}
CREATE RECURRING JOB RULE
diff --git a/apps/rowboat/app/projects/[projectId]/manage-triggers/components/recurring-job-rules-list.tsx b/apps/rowboat/app/projects/[projectId]/manage-triggers/components/recurring-job-rules-list.tsx index d5444eaa..73fd582c 100644 --- a/apps/rowboat/app/projects/[projectId]/manage-triggers/components/recurring-job-rules-list.tsx +++ b/apps/rowboat/app/projects/[projectId]/manage-triggers/components/recurring-job-rules-list.tsx @@ -8,7 +8,8 @@ import { listRecurringJobRules, deleteRecurringJobRule } from "@/app/actions/rec import { z } from "zod"; import { ListedRecurringRuleItem } from "@/src/application/repositories/recurring-job-rules.repository.interface"; import { isToday, isThisWeek, isThisMonth } from "@/lib/utils/date"; -import { PlusIcon, Trash2 } from "lucide-react"; +import { PlusIcon, Trash2, ArrowLeftIcon } from "lucide-react"; +import { CreateRecurringJobRuleForm } from "./create-recurring-job-rule-form"; type ListedItem = z.infer; @@ -19,6 +20,7 @@ export function RecurringJobRulesList({ projectId }: { projectId: string }) { const [loadingMore, setLoadingMore] = useState(false); const [hasMore, setHasMore] = useState(false); const [deletingRule, setDeletingRule] = useState(null); + const [showCreateForm, setShowCreateForm] = useState(false); const fetchPage = useCallback(async (cursorArg?: string | null) => { const res = await listRecurringJobRules({ projectId, cursor: cursorArg ?? undefined, limit: 20 }); @@ -39,6 +41,12 @@ export function RecurringJobRulesList({ projectId }: { projectId: string }) { return () => { ignore = true; }; }, [fetchPage]); + useEffect(() => { + if (!loading && items.length === 0 && !showCreateForm) { + setShowCreateForm(true); + } + }, [loading, items.length, showCreateForm]); + const loadMore = useCallback(async () => { if (!cursor) return; setLoadingMore(true); @@ -49,6 +57,24 @@ export function RecurringJobRulesList({ projectId }: { projectId: string }) { setLoadingMore(false); }, [cursor, fetchPage]); + const handleCreateNew = () => { + setShowCreateForm(true); + }; + + const handleBackToList = () => { + setShowCreateForm(false); + // Reload the list in case new triggers were created + const reload = async () => { + setLoading(true); + const res = await fetchPage(null); + setItems(res.items); + setCursor(res.nextCursor); + setHasMore(Boolean(res.nextCursor)); + setLoading(false); + }; + reload(); + }; + const handleDeleteRule = async (ruleId: string) => { if (!window.confirm('Are you sure you want to delete this recurring trigger?')) { return; @@ -125,6 +151,10 @@ export function RecurringJobRulesList({ projectId }: { projectId: string }) { return cron; }; + if (showCreateForm) { + return 0} />; + } + return ( - - - + } > diff --git a/apps/rowboat/app/projects/[projectId]/manage-triggers/components/triggers-tab.tsx b/apps/rowboat/app/projects/[projectId]/manage-triggers/components/triggers-tab.tsx index ede8bf28..e18c42ba 100644 --- a/apps/rowboat/app/projects/[projectId]/manage-triggers/components/triggers-tab.tsx +++ b/apps/rowboat/app/projects/[projectId]/manage-triggers/components/triggers-tab.tsx @@ -205,6 +205,12 @@ export function TriggersTab({ projectId }: { projectId: string }) { } }, [showCreateFlow, loadTriggers]); + useEffect(() => { + if (!loading && !error && triggers.length === 0 && !showCreateFlow) { + setShowCreateFlow(true); + } + }, [loading, error, triggers.length, showCreateFlow]); + useEffect(() => { // No-op: trigger names are now derived from slug locally }, [triggers]); @@ -457,14 +463,16 @@ export function TriggersTab({ projectId }: { projectId: string }) {

Select a Toolkit to Create Trigger

- + {triggers.length > 0 && ( + + )} void; hasExistingTriggers?: boolean }) { const router = useRouter(); const [loading, setLoading] = useState(false); const [messages, setMessages] = useState([ @@ -90,7 +90,11 @@ export function CreateScheduledJobRuleForm({ projectId }: { projectId: string }) input: { messages: convertedMessages }, scheduledTime: scheduledTimeString, }); - router.push(`/projects/${projectId}/manage-triggers?tab=scheduled`); + if (onBack) { + onBack(); + } else { + router.push(`/projects/${projectId}/manage-triggers?tab=scheduled`); + } } catch (error) { console.error("Failed to create scheduled job rule:", error); alert("Failed to create scheduled job rule"); @@ -105,11 +109,17 @@ export function CreateScheduledJobRuleForm({ projectId }: { projectId: string }) - - - + ) : hasExistingTriggers ? ( + + + + ) : null}
CREATE SCHEDULED JOB RULE
diff --git a/apps/rowboat/app/projects/[projectId]/manage-triggers/scheduled/components/scheduled-job-rules-list.tsx b/apps/rowboat/app/projects/[projectId]/manage-triggers/scheduled/components/scheduled-job-rules-list.tsx index b8baf176..cd7ef7be 100644 --- a/apps/rowboat/app/projects/[projectId]/manage-triggers/scheduled/components/scheduled-job-rules-list.tsx +++ b/apps/rowboat/app/projects/[projectId]/manage-triggers/scheduled/components/scheduled-job-rules-list.tsx @@ -9,6 +9,7 @@ import { z } from "zod"; import { ListedRuleItem } from "@/src/application/repositories/scheduled-job-rules.repository.interface"; import { isToday, isThisWeek, isThisMonth } from "@/lib/utils/date"; import { PlusIcon, Trash2 } from "lucide-react"; +import { CreateScheduledJobRuleForm } from "./create-scheduled-job-rule-form"; type ListedItem = z.infer; @@ -19,6 +20,7 @@ export function ScheduledJobRulesList({ projectId }: { projectId: string }) { const [loadingMore, setLoadingMore] = useState(false); const [hasMore, setHasMore] = useState(false); const [deletingRule, setDeletingRule] = useState(null); + const [showCreateFlow, setShowCreateFlow] = useState(false); const fetchPage = useCallback(async (cursorArg?: string | null) => { const res = await listScheduledJobRules({ projectId, cursor: cursorArg ?? undefined, limit: 20 }); @@ -39,6 +41,12 @@ export function ScheduledJobRulesList({ projectId }: { projectId: string }) { return () => { ignore = true; }; }, [fetchPage]); + useEffect(() => { + if (!loading && items.length === 0 && !showCreateFlow) { + setShowCreateFlow(true); + } + }, [loading, items.length, showCreateFlow]); + const loadMore = useCallback(async () => { if (!cursor) return; setLoadingMore(true); @@ -67,6 +75,29 @@ export function ScheduledJobRulesList({ projectId }: { projectId: string }) { } }; + const handleCreateNew = () => { + setShowCreateFlow(true); + }; + + const handleBackToList = () => { + setShowCreateFlow(false); + // Reload the list to show any newly created triggers + const loadTriggers = async () => { + try { + setLoading(true); + const response = await fetchPage(null); + setItems(response.items); + setCursor(response.nextCursor); + setHasMore(Boolean(response.nextCursor)); + } catch (err: any) { + console.error('Error loading triggers:', err); + } finally { + setLoading(false); + } + }; + loadTriggers(); + }; + const sections = useMemo(() => { const groups: Record = { Today: [], @@ -103,6 +134,10 @@ export function ScheduledJobRulesList({ projectId }: { projectId: string }) { return date.toLocaleString(); }; + if (showCreateFlow) { + return 0} />; + } + return ( - - - + } >