diff --git a/frontend/src/api/steps.ts b/frontend/src/api/steps.ts index 4b63762e..f250c722 100644 --- a/frontend/src/api/steps.ts +++ b/frontend/src/api/steps.ts @@ -45,7 +45,7 @@ export const stepsApi = { }, async getPopularTags(): Promise { - const response = await apiClient.get('/steps/popular-tags') + const response = await apiClient.get('/steps/tags/popular') return response.data }, diff --git a/frontend/src/components/session/ContinuationModal.tsx b/frontend/src/components/session/ContinuationModal.tsx new file mode 100644 index 00000000..2b13b002 --- /dev/null +++ b/frontend/src/components/session/ContinuationModal.tsx @@ -0,0 +1,139 @@ +import { Modal } from '@/components/common/Modal' +import { ArrowRight, GitBranch, AlertTriangle, HelpCircle, Zap, CheckCircle } from 'lucide-react' +import { cn } from '@/lib/utils' +import type { NodeType } from '@/types/tree' + +export interface DescendantNode { + id: string + label: string + type: NodeType + parentOptionLabel: string +} + +interface ContinuationModalProps { + isOpen: boolean + onClose: () => void + descendantNodes: DescendantNode[] + onSelectNode: (nodeId: string) => void + onBuildCustomBranch: () => void +} + +const nodeTypeIcons: Record = { + decision: , + action: , + solution: +} + +const nodeTypeLabels: Record = { + decision: 'Decision', + action: 'Action', + solution: 'Solution' +} + +export function ContinuationModal({ + isOpen, + onClose, + descendantNodes, + onSelectNode, + onBuildCustomBranch +}: ContinuationModalProps) { + // Group nodes by parent option + const groupedNodes = descendantNodes.reduce((acc, node) => { + if (!acc[node.parentOptionLabel]) { + acc[node.parentOptionLabel] = [] + } + acc[node.parentOptionLabel].push(node) + return acc + }, {} as Record) + + const hasDescendants = descendantNodes.length > 0 + + return ( + +
+ {/* Descendant Selection */} + {hasDescendants && ( +
+

+ Select the next step in your troubleshooting path: +

+ +
+ {Object.entries(groupedNodes).map(([parentOption, nodes]) => ( +
+

+ From: {parentOption} +

+
+ {nodes.map(node => ( + + ))} +
+
+ ))} +
+
+ )} + + {/* Divider */} + {hasDescendants && ( +
+
+ + Or + +
+
+ )} + + {/* Build Custom Branch */} +
+ + + {/* Warning */} +
+ +

+ You'll need to complete this branch manually or mark the issue as resolved. + Custom branches can be saved as a personal tree when your session ends. +

+
+
+
+ + ) +} diff --git a/frontend/src/components/session/ForkTreeModal.tsx b/frontend/src/components/session/ForkTreeModal.tsx new file mode 100644 index 00000000..072e6b8a --- /dev/null +++ b/frontend/src/components/session/ForkTreeModal.tsx @@ -0,0 +1,144 @@ +import { useState } from 'react' +import { Modal } from '@/components/common/Modal' +import { GitFork, Loader2 } from 'lucide-react' +import { cn } from '@/lib/utils' + +interface ForkTreeModalProps { + isOpen: boolean + onClose: () => void + originalTreeName: string + onFork: (name: string, description: string) => Promise + onSkip: () => void +} + +export function ForkTreeModal({ + isOpen, + onClose, + originalTreeName, + onFork, + onSkip +}: ForkTreeModalProps) { + const [name, setName] = useState(`${originalTreeName} (Custom)`) + const [description, setDescription] = useState('') + const [isSaving, setIsSaving] = useState(false) + const [error, setError] = useState(null) + + const handleFork = async () => { + if (!name.trim()) { + setError('Please enter a name for your tree') + return + } + + setIsSaving(true) + setError(null) + + try { + await onFork(name.trim(), description.trim()) + } catch (err) { + setError('Failed to save tree. Please try again.') + console.error(err) + } finally { + setIsSaving(false) + } + } + + const footer = ( +
+ + +
+ ) + + return ( + +
+
+
+ +
+
+

You've created a custom troubleshooting path!

+

+ Save it as your own personal tree to reuse this troubleshooting flow in the future. +

+
+
+ +
+
+ + setName(e.target.value)} + placeholder="My Custom Tree" + className={cn( + 'w-full rounded-md border border-input bg-background px-3 py-2 text-sm', + 'focus:outline-none focus:ring-2 focus:ring-ring' + )} + /> +
+ +
+ +