/** * NodeSidebar - Sidebar with searchable, collapsible node list. * Groups node types by category (trigger, input, flow, data, ai, email, sharepoint). */ import React, { useMemo } from 'react'; import { FaChevronDown, FaChevronRight } from 'react-icons/fa'; import type { NodeType, NodeTypeCategory } from '../../api/automation2Api'; import { CATEGORY_ORDER, HIDDEN_NODE_IDS } from './constants'; import { getLabel } from './utils'; import { NodeListItem } from './NodeListItem'; import styles from './Automation2FlowEditor.module.css'; interface NodeSidebarProps { nodeTypes: NodeType[]; categories: NodeTypeCategory[]; filter: string; onFilterChange: (value: string) => void; language: string; expandedCategories: Set; onToggleCategory: (id: string) => void; } export const NodeSidebar: React.FC = ({ nodeTypes, categories, filter, onFilterChange, language, expandedCategories, onToggleCategory, }) => { const filteredNodeTypes = useMemo(() => { const visible = nodeTypes.filter((n) => !HIDDEN_NODE_IDS.has(n.id)); if (!filter.trim()) return visible; const q = filter.toLowerCase(); return visible.filter( (n) => n.id.toLowerCase().includes(q) || getLabel(n.label, language).toLowerCase().includes(q) || getLabel(n.description, language).toLowerCase().includes(q) ); }, [nodeTypes, filter, language]); const groupedByCategory = useMemo(() => { const map: Record = {}; filteredNodeTypes.forEach((n) => { const cat = n.category || 'other'; if (!map[cat]) map[cat] = []; map[cat].push(n); }); return map; }, [filteredNodeTypes]); const orderedCategories = useMemo(() => { const seen = new Set(); const result: string[] = []; CATEGORY_ORDER.forEach((id) => { if (groupedByCategory[id]) { result.push(id); seen.add(id); } }); Object.keys(groupedByCategory).forEach((id) => { if (!seen.has(id)) result.push(id); }); return result; }, [groupedByCategory]); const getLabelFn = (t: string | Record | undefined, lang?: string) => getLabel(t, lang ?? language); return (

Nodes

onFilterChange(e.target.value)} />
{orderedCategories.map((catId) => { const isExpanded = expandedCategories.has(catId); const catLabel = categories.find((c) => c.id === catId); const label = getLabel(catLabel?.label, language) || catId; const items = groupedByCategory[catId] || []; return (
{isExpanded && items.map((node) => ( ))}
); })}
); };