diff --git a/frontend/src/pages/TreeLibraryPage.tsx b/frontend/src/pages/TreeLibraryPage.tsx index 63d8e7d3..603ca4b5 100644 --- a/frontend/src/pages/TreeLibraryPage.tsx +++ b/frontend/src/pages/TreeLibraryPage.tsx @@ -1,6 +1,6 @@ import { useEffect, useState, useCallback } from 'react' import { useNavigate, Link, useSearchParams } from 'react-router-dom' -import { Plus, X, RotateCcw, Play } from 'lucide-react' +import { Plus, X, RotateCcw, Play, ChevronDown, Sparkles, FolderTree, ListOrdered, Wrench } from 'lucide-react' import { treesApi } from '@/api/trees' import { categoriesApi } from '@/api/categories' import { foldersApi } from '@/api/folders' @@ -17,6 +17,9 @@ import { cn, safeGetItem } from '@/lib/utils' import { getSessionResumePath } from '@/lib/routing' import { usePermissions } from '@/hooks/usePermissions' import { useUserPreferencesStore } from '@/store/userPreferencesStore' +import { usePinnedFlowsStore, selectPinnedTreeIds, selectPinLoadingTreeIds } from '@/store/pinnedFlowsStore' +import { useCachedQuota } from '@/hooks/useCachedQuota' +import { AIFlowBuilderModal } from '@/components/ai-builder/AIFlowBuilderModal' import { toast } from '@/lib/toast' export function TreeLibraryPage() { @@ -69,6 +72,17 @@ export function TreeLibraryPage() { // Fork state const [isForkingTree, setIsForkingTree] = useState(false) + // Create menu & AI builder state + const [showCreateMenu, setShowCreateMenu] = useState(false) + const [showAIBuilder, setShowAIBuilder] = useState(false) + const { aiEnabled } = useCachedQuota() + + // Pin store + const pinnedTreeIds = usePinnedFlowsStore(selectPinnedTreeIds) + const pinLoadingTreeIds = usePinnedFlowsStore(selectPinLoadingTreeIds) + const togglePin = usePinnedFlowsStore((s) => s.toggle) + const loadPinned = usePinnedFlowsStore((s) => s.load) + // Repeat Last Session const lastSessionData = (() => { const raw = safeGetItem('last-session') @@ -102,6 +116,9 @@ export function TreeLibraryPage() { .catch((err) => console.error('Failed to load incomplete sessions:', err)) }, []) + // Load pinned flows + useEffect(() => { loadPinned() }, [loadPinned]) + const dismissSession = (sessionId: string) => { const next = new Set(dismissedSessionIds) next.add(sessionId) @@ -263,16 +280,78 @@ export function TreeLibraryPage() {

{canCreateTrees && ( - + + {showCreateMenu && ( + <> +
setShowCreateMenu(false)} /> +
+ setShowCreateMenu(false)} + className="flex items-center gap-3 rounded-md px-3 py-2.5 text-sm text-foreground hover:bg-accent" + > + +
+
Troubleshooting Tree
+
Branching decision flow
+
+ + setShowCreateMenu(false)} + className="flex items-center gap-3 rounded-md px-3 py-2.5 text-sm text-foreground hover:bg-accent" + > + +
+
Procedural Flow
+
Step-by-step procedure
+
+ + setShowCreateMenu(false)} + className="flex items-center gap-3 rounded-md px-3 py-2.5 text-sm text-foreground hover:bg-accent" + > + +
+
Maintenance Flow
+
Scheduled multi-target tasks
+
+ + {aiEnabled && ( + <> +
+ + + )} +
+ )} - > - - {typeFilter === 'procedural' ? 'New Project' : typeFilter === 'maintenance' ? 'New Maintenance Flow' : 'Create Flow'} - +
)}
@@ -474,6 +553,9 @@ export function TreeLibraryPage() { setShowDeleteConfirm(true) }} onForkTree={handleForkTree} + pinnedTreeIds={pinnedTreeIds} + onTogglePin={togglePin} + pinLoadingTreeIds={pinLoadingTreeIds} /> )} {treeLibraryView === 'list' && ( @@ -487,6 +569,9 @@ export function TreeLibraryPage() { setShowDeleteConfirm(true) }} onForkTree={handleForkTree} + pinnedTreeIds={pinnedTreeIds} + onTogglePin={togglePin} + pinLoadingTreeIds={pinLoadingTreeIds} /> )} {treeLibraryView === 'table' && ( @@ -505,6 +590,9 @@ export function TreeLibraryPage() { ) }} onForkTree={handleForkTree} + pinnedTreeIds={pinnedTreeIds} + onTogglePin={togglePin} + pinLoadingTreeIds={pinLoadingTreeIds} /> )} @@ -538,6 +626,14 @@ export function TreeLibraryPage() { confirmVariant="destructive" isLoading={isDeleting} /> + + {/* AI Builder Modal */} + {showAIBuilder && ( + setShowAIBuilder(false)} + /> + )} ) }