--- description: "Guidelines for frontend development in Langflow, focusing on React/TypeScript UI components, build processes, and frontend testing." globs: - "src/frontend/**/*.{ts,tsx,js,jsx}" - "src/frontend/**/*.{css,scss,json}" - "src/frontend/package*.json" - "src/frontend/vite.config.*" - "src/frontend/tailwind.config.*" - "src/frontend/tsconfig.json" alwaysApply: false --- ## 1. Frontend Environment Setup ### Prerequisites - **Node.js:** v22.12 LTS for JavaScript runtime - **Package Manager:** npm (v10.9) for dependency management - **Development Tools:** Vite for build tooling ### Frontend Service ```bash make frontend # Start Vite dev server on port 3000 ``` - Hot-reload enabled for UI changes - Access at: http://localhost:3000/ - Frontend source: `src/frontend/` --- ## 2. Frontend Structure ### Directory Layout ``` src/frontend/src/ ├── components/ # Reusable UI components ├── pages/ # Page-level components ├── icons/ # Component icons and lazy loading ├── stores/ # State management (Zustand) ├── types/ # TypeScript type definitions ├── utils/ # Utility functions ├── hooks/ # Custom React hooks ├── services/ # API service functions └── assets/ # Static assets ``` ### Key Technologies - **React 18** with TypeScript - **Vite** for build tooling and dev server - **Tailwind CSS** for styling - **Zustand** for state management - **React Flow** for flow graph visualization - **Lucide React** for icons --- ## 3. Frontend Code Quality ### Formatting ```bash make format_frontend # Format TypeScript/JavaScript code ``` ### Linting ```bash make lint # Run ESLint and TypeScript checks ``` ### Testing ```bash make tests_frontend # Run frontend tests (requires additional setup) ``` ### Pre-commit Workflow 1. Run `make format_frontend` 2. Run `make lint` 3. Test changes in browser 4. Commit changes --- ## 4. State Management ### Zustand Stores ```typescript // stores/myStore.ts import { create } from 'zustand'; interface MyState { value: string; setValue: (value: string) => void; } export const useMyStore = create((set) => ({ value: '', setValue: (value) => set({ value }), })); ``` ### Using Stores in Components ```typescript // components/MyComponent.tsx import { useMyStore } from '@/stores/myStore'; export function MyComponent() { const { value, setValue } = useMyStore(); return ( setValue(e.target.value)} /> ); } ``` --- ## 5. API Integration ### Service Functions ```typescript // services/api.ts import { api } from '@/controllers/API'; export async function createFlow(flowData: FlowData) { const response = await api.post('/flows/', flowData); return response.data; } export async function getFlows() { const response = await api.get('/flows/'); return response.data; } ``` ### Error Handling ```typescript // hooks/useApi.ts import { useState, useCallback } from 'react'; export function useApi(apiFunction: (...args: any[]) => Promise) { const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const execute = useCallback(async (...args: any[]) => { try { setLoading(true); setError(null); const result = await apiFunction(...args); return result; } catch (err) { setError(err instanceof Error ? err.message : 'Unknown error'); throw err; } finally { setLoading(false); } }, [apiFunction]); return { execute, loading, error }; } ``` --- ## 6. React Flow Integration ### Flow Graph Components ```typescript // components/FlowGraph.tsx import ReactFlow, { Node, Edge, Controls, Background } from 'reactflow'; interface FlowGraphProps { nodes: Node[]; edges: Edge[]; onNodesChange: (changes: NodeChange[]) => void; onEdgesChange: (changes: EdgeChange[]) => void; } export function FlowGraph({ nodes, edges, onNodesChange, onEdgesChange }: FlowGraphProps) { return (
); } ``` ### Custom Node Types ```typescript // components/nodes/ComponentNode.tsx import { memo } from 'react'; import { Handle, Position } from 'reactflow'; interface ComponentNodeProps { data: { label: string; icon?: string; }; } export const ComponentNode = memo(({ data }: ComponentNodeProps) => { return (
{data.icon && ( )} {data.label}
); }); ``` --- ## 7. Styling with Tailwind ### Component Styling ```typescript // components/Button.tsx import { cn } from '@/utils/cn'; interface ButtonProps { variant?: 'primary' | 'secondary'; size?: 'sm' | 'md' | 'lg'; children: React.ReactNode; onClick?: () => void; } export function Button({ variant = 'primary', size = 'md', children, onClick }: ButtonProps) { return ( ); } ``` ### Dark Mode Support ```typescript // hooks/useDarkMode.ts import { useDarkStore } from '@/stores/darkStore'; export function useDarkMode() { const { dark, setDark } = useDarkStore(); const toggle = () => setDark(!dark); return { isDark: dark, toggle }; } ``` --- ## 8. Frontend Testing ### Component Testing ```typescript // __tests__/Button.test.tsx import { render, screen, fireEvent } from '@testing-library/react'; import { Button } from '@/components/Button'; describe('Button', () => { it('renders with correct text', () => { render(); expect(screen.getByText('Click me')).toBeInTheDocument(); }); it('calls onClick when clicked', () => { const handleClick = jest.fn(); render(); fireEvent.click(screen.getByText('Click me')); expect(handleClick).toHaveBeenCalledTimes(1); }); }); ``` ### Integration Testing ```typescript // __tests__/FlowEditor.test.tsx import { render, screen } from '@testing-library/react'; import { FlowEditor } from '@/pages/FlowEditor'; describe('FlowEditor', () => { it('loads flow data correctly', async () => { render(); // Wait for flow to load await screen.findByText('Flow loaded'); expect(screen.getByTestId('flow-canvas')).toBeInTheDocument(); }); }); ``` --- ## 9. Build and Deployment ### Development Build ```bash make build_frontend # Build frontend static files ``` ### Production Build ```bash cd src/frontend npm run build # Creates dist/ directory ``` ### Build Integration - Frontend builds to `src/frontend/dist/` - Backend serves static files from this directory in production - `make init` includes frontend build step --- ## Frontend Development Checklist - [ ] Frontend service running with `make frontend` - [ ] Changes hot-reload correctly in browser - [ ] State management uses Zustand stores - [ ] API calls use proper error handling - [ ] Components styled with Tailwind CSS - [ ] Dark mode support implemented where needed - [ ] Code formatted with `make format_frontend` - [ ] Linting passed with `make lint` - [ ] Changes tested in both light and dark mode - [ ] Components styled with Tailwind CSS - [ ] Dark mode support implemented where needed - [ ] Code formatted with `make format_frontend` - [ ] Changes tested in both light and dark mode