Allow zooming out to 10% (previously 50%) to better accommodate large constellation analyses. Added zoom constants (MIN_ZOOM=0.1, MAX_ZOOM=2.5) for consistency across fitView and ReactFlow component.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Remove three unnecessary eslint-disable comments for @typescript-eslint/no-unused-vars
that were no longer needed, as the destructured variables are actually used.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add double-click handler for minimized groups to quickly maximize them,
providing a faster alternative to using the context menu.
Implementation:
- Add handleNodeDoubleClick callback in GraphEditor
- Check if double-clicked node is a minimized group
- Call toggleGroupMinimized to maximize the group
- Wire handler to ReactFlow's onNodeDoubleClick prop
This improves UX by allowing users to quickly expand minimized groups
to see and edit individual relations within them.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implements visual aggregation of edges when multiple relations exist
between two minimized groups, preventing overlapping edges and improving
graph readability.
Key features:
- Aggregate edges between minimized groups using normalized keys (sorted
node IDs) so bidirectional edges (A->B and B->A) merge together
- Display single neutral-styled edge (dark gray, solid, no arrows) with
relation counter badge showing "X relations"
- Disable context menu and use special info panel for aggregated edges
- Hide individual edge type labels when aggregated
- Store all original relation data in aggregatedRelations array
Implementation details:
- GraphEditor: Use Map to deduplicate edges with bidirectional key for
group-to-group connections, attach aggregatedCount metadata
- CustomEdge: Detect aggregated edges and apply neutral styling (#4b5563
color, undirected/no arrows, no type label)
- RightPanel: Show "Aggregated Relations" info panel instead of
EdgeEditorPanel for aggregated edges
- Context menu: Skip aggregated edges to prevent editing synthetic edges
Users can maximize groups to see and edit individual relations. This
keeps the graph clean when working with minimized groups while preserving
all underlying relationship data.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implements proper edge rendering when both source and target actors are
in minimized groups. Edges are now correctly rerouted to connect the
minimized group nodes with dynamic floating edge calculations.
Key changes:
- Add edge rerouting logic to redirect edges from hidden actors to their
parent minimized groups
- Implement edge deduplication to prevent multiple edges between same
groups when multiple actors have connections
- Fix floating edge calculations with fallback dimensions to prevent NaN
- Use canonical parentId property instead of actorIds array for accuracy
- Create constants.ts for MINIMIZED_GROUP_WIDTH/HEIGHT (220x80)
- Replace magic numbers throughout codebase with named constants
- Remove sourceHandle/targetHandle properties when routing to groups to
avoid React Flow validation errors
Technical details:
- GraphEditor: Build actor-to-group mapping using parentId, deduplicate
edges with Map keyed by source_target, strip handle properties
- CustomEdge: Use floating edge params for minimized groups on both ends
- edgeUtils: Add fallback dimensions and division-by-zero guards in
getNodeIntersection and getEdgePosition
- graphStore: Use constants for minimized group dimensions
Edges between minimized groups now render with proper Bezier curves and
dynamic connection points that adapt to group positions.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implements comprehensive multi-selection support for bulk operations on
actors, relations, and groups.
Features:
- New MultiSelectProperties panel for 2+ selected elements
- Bulk operations: group, ungroup, delete, minimize/maximize
- Add actors to existing groups (expands group bounds)
- Reverse relation directions
- Change directionality for multiple relations
- Immediate UI feedback with local state for directionality
- Standardized panel layout with scrollable content and footer
Fixes:
- Group positioning: actors stay at absolute positions when added/removed
- Minimize/maximize: properly stores/restores dimensions and visibility
- Position conversion between absolute and relative coordinates
- Type-safe width/height handling for group dimensions
UI Consistency:
- All property panels use fragment wrapper pattern
- Scrollable content area with px-3 py-3 padding
- Fixed footer section with action buttons
- Consistent button styles across panels
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Edge labels were appearing behind edges when a group was selected
because React Flow elevates selected nodes to z-index ~1000, bringing
their child edges above the edge labels.
Solution:
- Increased edge label z-index from 1000 to 1100
- Ensures labels always render on top of edges, even in selected groups
The issue occurred because:
1. Edge labels use EdgeLabelRenderer (separate overlay layer)
2. When groups are selected, React Flow increases their z-index
3. Group edges (SVG elements) inherit the elevated z-index
4. Edge labels at z-index 1000 were below the elevated edges
By setting edge labels to z-index 1100, they now consistently
render above all edges regardless of selection state.
Benefits:
- ✅ Edge labels always readable, even with selected groups
- ✅ Consistent label visibility across all interaction states
- ✅ Better UX for understanding relationships in groups
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Maximized groups now display their assigned background color instead
of using the hardcoded default gray color.
Changes:
GroupNode.tsx:
- Added background color overlay div in maximized state
- Uses data.color property (same as minimized groups)
- Positioned absolutely to fill entire group area
- Set pointerEvents: 'none' to allow interaction with children
index.css:
- Changed .react-flow__node-group background to transparent
- Changed .react-flow__node-group.selected background to transparent
- Inner div now controls the background color
This ensures visual consistency between minimized and maximized
groups - both now respect the user-selected color from the group
properties panel.
Benefits:
- ✅ Visual consistency between group states
- ✅ User-selected colors are always visible
- ✅ Better visual organization with color-coded groups
- ✅ Matches user expectations for group appearance
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Applied luminosity-based contrast color calculation to minimized
group labels, matching the same accessibility approach used for
actor nodes.
Changes:
- Added rgbToHex() helper to convert rgb/rgba colors to hex format
- Import getContrastColor() from colorUtils
- Calculate text color based on background luminosity
- Apply calculated color to both label and subtitle
Typography updates to match actor nodes:
- Main label: text-base font-bold (was text-sm font-semibold)
- Subtitle: text-xs font-medium with 0.7 opacity (was text-gray-600)
- Both use dynamic textColor instead of fixed gray values
Benefits:
- ✅ Readable labels on both light and dark group backgrounds
- ✅ Consistent typography between actor nodes and group nodes
- ✅ Follows WCAG 2.0 luminance contrast standards
- ✅ Professional appearance across all color choices
The minimized group labels now automatically switch between white
and black text based on the background color's luminosity, ensuring
optimal readability in all cases.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
The group property panel's minimize/maximize button label was not
updating after clicking because it relied on the selectedGroup prop
passed from the parent, which was set once on selection and never
updated when the group's minimized state changed in the store.
Changes:
- Added currentGroup lookup from the store's groups array
- Use currentGroup (from store) for minimized state checks
- Button label now reflects the actual current state
This ensures the button always shows the correct action based on
the group's actual minimized state in the store, not the stale
prop value.
Fixes the issue where clicking "Minimize Group" would minimize the
group visually but the button would still say "Minimize Group"
instead of changing to "Maximize Group".
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implements comprehensive group minimize/maximize functionality and migrates
to React Flow v12 (@xyflow/react) with improved edge routing.
## Group Minimize/Maximize Features:
- Minimized groups render as compact 220×80px solid rectangles
- Original dimensions preserved in metadata and restored on maximize
- Child actors hidden (not filtered) to prevent React Flow state issues
- Solid color backgrounds (transparency removed for minimized state)
- Internal edges filtered out when group is minimized
- Dimension sync before minimize ensures correct size on maximize
## Floating Edges:
- Dynamic edge routing for connections to/from minimized groups
- Edges connect to closest point on minimized group border
- Regular actors maintain fixed handle connections
- Smooth transitions when toggling group state
## React Flow v12 Migration:
- Updated package from 'reactflow' to '@xyflow/react'
- Changed imports to named imports (ReactFlow is now named)
- Updated CSS imports to '@xyflow/react/dist/style.css'
- Fixed NodeProps/EdgeProps to use full Node/Edge types
- Added Record<string, unknown> to data interfaces for v12 compatibility
- Replaced useStore(state => state.connectionNodeId) with useConnection()
- Updated nodeInternals to nodeLookup (renamed in v12)
- Fixed event handler types for v12 API changes
## Edge Label Improvements:
- Added explicit z-index (1000) to edge labels via EdgeLabelRenderer
- Labels now properly render above edge paths
## Type Safety & Code Quality:
- Removed all 'any' type assertions in useDocumentHistory
- Fixed missing React Hook dependencies
- Fixed unused variable warnings
- All ESLint checks passing (0 errors, 0 warnings)
- TypeScript compilation clean
## Bug Fixes:
- Group drag positions now properly persisted to store
- Minimized group styling (removed dotted border, padding)
- Node visibility using 'hidden' property instead of array filtering
- Dimension sync prevents actors from disappearing on maximize
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implements visual grouping of actors with context menu operations,
resizable containers, and complete history tracking integration.
Features:
- Create groups from multiple selected actors via context menu
- Groups visualized as resizable containers with child nodes
- Ungroup actors (non-destructive) or delete group with actors
- Right-click context menu with group-specific operations
- Dedicated GroupEditorPanel for group properties
- Smart minimum size constraint based on child node positions
- Full undo/redo support for group operations and resizes
Technical Implementation:
- GroupNode component with React Flow NodeResizer integration
- Atomic createGroupWithActors operation for consistent history
- Parent-child relationship using React Flow v11 parentId pattern
- Groups stored separately from actors in graphStore
- Fixed history tracking to sync graphStore before snapshots
- Resize tracking to prevent state sync loops during interaction
- Dynamic minimum dimensions to keep children inside bounds
- Sanitization of orphaned parentId references on state load
History Fixes:
- pushToHistory now syncs timeline with graphStore before snapshot
- Prevents missing groups/nodes in history states
- Ensures undo/redo correctly restores all graph elements
- Atomic state updates to avoid React Flow processing stale state
Storage & Persistence:
- Groups saved in timeline states and document structure
- Safe JSON serialization to prevent prototype pollution
- Cleanup utilities for removing __proto__ from localStorage
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Replaces Material-UI components in Timeline dialogs with custom Tailwind
CSS styling to match the application's standard dialog design.
Changes:
- RenameStateDialog: Replaced MUI Dialog, TextField, and Button components
with custom styled elements matching ConfirmDialog/InputDialog pattern
- CreateStateDialog: Converted all MUI form components (TextField, Checkbox,
Button) to native HTML elements with Tailwind styling
- Added consistent visual design with large icons, gray backgrounds, and
proper spacing
- Improved keyboard handling (Enter/Escape) with proper event listeners
- Enhanced focus management with auto-select on input fields
- Maintained all existing functionality while improving UI consistency
Both dialogs now feature:
- Icon-based visual hierarchy with 48px icons
- Consistent button styling (gray cancel, blue confirm)
- Proper disabled states and hover effects
- Gray-50 background on action button areas
- Backdrop click to close
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Adds detection and parsing support for more input formats that
citation.js can handle, making the smart import feature more powerful.
New supported formats:
- RIS format (common export from EndNote, RefWorks, Zotero)
- PubMed Central IDs (PMCID) in addition to existing PMID support
- Wikidata IDs (e.g., Q12345 or wikidata:Q12345)
- Zenodo records (URLs and IDs like zenodo.1234567)
- Citation File Format (CFF) for software citations
Benefits:
- Users can now paste RIS exports from reference managers directly
- Support for Wikidata citations enables citing entities/concepts
- Zenodo support facilitates citing datasets and research outputs
- CFF support enables proper software citation
- Enhanced format detection provides better user feedback
The smart parser now detects all these formats automatically and
displays the appropriate format hint to users. All formats are
processed through citation.js's robust parsing engine.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implements complete bibliography management with citation assignment to
nodes and edges, following CSL-JSON standard.
Features:
- Bibliography store with Zustand and citation.js integration
- Smart import supporting DOI, BibTeX, PubMed ID, and URLs
- Manual entry and editing forms for references
- Citation selector with autocomplete text field interface
- History tracking for undo/redo support
- Workspace integration for import/export
- Support for multiple reference types including interview and other
- Description/notes field for additional reference information
Components:
- CitationSelector: autocomplete UI for selecting citations
- BibliographyConfigModal: main bibliography management interface
- QuickAddReferenceForm: smart import and manual entry
- EditReferenceInline: full reference editing form
- ReferenceManagementList: list view with citation counts
Integration:
- NodeEditorPanel: citation assignment to actors
- EdgeEditorPanel: citation assignment to relations
- MenuBar: bibliography menu item
- WorkspaceStore: bibliography persistence in workspace files
Technical details:
- CSL-JSON format for bibliographic data
- citation.js for parsing and formatting
- TypeScript with proper type definitions
- Debounced updates for performance
- Citation count tracking across graph elements
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Update generateRandomColor to return hex codes instead of HSL strings
to ensure proper color storage in database.
Changes:
- Add hslToHex conversion function
- Maintain same pastel color generation (random hue, 70% saturation, 65% lightness)
- Return hex format (#rrggbb) instead of HSL string
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add quick access edit button next to "Labels" field in both Node Editor
and Edge Editor panels, matching the existing pattern for Actor Type and
Relation Type edit buttons.
Changes:
- Add small edit icon button next to Labels field
- Opens LabelConfigModal for managing label definitions
- Consistent UX with existing type configuration buttons
- Available in both NodeEditorPanel and EdgeEditorPanel
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Improves code organization and maintainability by separating panel
implementations into focused, single-responsibility components.
Changes:
- Extract NodeEditorPanel for actor property editing
- Extract EdgeEditorPanel for relation property editing
- Extract GraphAnalysisPanel for graph metrics display
- Simplify RightPanel to act as routing/layout component (745→114 lines)
- Remove old unused Editor/NodePropertiesPanel.tsx
- Remove old unused Editor/EdgePropertiesPanel.tsx
All existing functionality preserved including live updates, debouncing,
modals, and connection displays. Each panel now self-contained with its
own state management and logic.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implements a comprehensive label system and completely redesigns all
filtering (labels, actor types, relation types) to use intuitive positive
filtering where empty selection shows all items.
Label System Features:
- Create, edit, delete labels with names, colors, and scope (actors/relations/both)
- Inline editing with click-to-edit UI for quick modifications
- Quick-add label forms in config modals
- Autocomplete label selector with inline label creation
- Label badges rendered on nodes and edges (no overflow limits)
- Full undo/redo support for label operations
- Label validation and cleanup when labels are deleted
- Labels stored per-document in workspace system
Filter System Redesign:
- Changed from negative to positive filtering for all filter types
- Empty selection = show all items (intuitive default)
- Selected items = show only those items (positive filter)
- Consistent behavior across actor types, relation types, and labels
- Clear visual feedback with selection counts and helper text
- Auto-zoom viewport adjustment works for all filter types including labels
Label Cleanup & Validation:
- When label deleted, automatically removed from all nodes/edges across all timeline states
- Label references validated during node/edge updates
- Unknown label IDs filtered out to maintain data integrity
UI Improvements:
- All labels rendered without overflow limits (removed +N more indicators)
- Filter checkboxes start unchecked (select to filter, not hide)
- Helper text explains current filter state
- Selection counts displayed in filter section headers
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Adds a small edit icon button next to the "Relation Type" label in the
RightPanel Relation Properties section that opens the EdgeTypeConfigModal
directly in edit mode for the selected relation's type.
Changes:
- Added edit icon button aligned to the right of "Relation Type" label
- Opens existing EdgeTypeConfigModal in edit mode for current type
- Enhanced EdgeTypeConfigModal to support initialEditingTypeId prop
- Modal automatically enters edit mode when opened with a type ID
This mirrors the actor type edit button functionality and provides a
convenient shortcut for editing relation types without navigating to
the settings menu or left panel configuration.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Adds a small edit icon button next to the "Actor Type" label in the
RightPanel Actor Properties section that opens the NodeTypeConfigModal
directly in edit mode for the selected actor's type.
Changes:
- Added edit icon button aligned to the right of "Actor Type" label
- Opens existing NodeTypeConfigModal in edit mode for current type
- Enhanced NodeTypeConfigModal to support initialEditingTypeId prop
- Modal automatically enters edit mode when opened with a type ID
- Fixed TypeScript error with showAdvancedByDefault prop
This provides a convenient shortcut for editing actor types without
navigating to the settings menu or left panel configuration.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Updates the relation type configuration to match the new actor type UX
with a modern two-column layout and streamlined workflows.
Changes to relation type configuration:
- Two-column layout: quick add (left) + management list (right)
- Inline editing replaces the right column when editing
- Single-row layout for name, color, and line style fields
- Line style preview with visual feedback
- White background cards with click-to-edit interaction
- Always-visible duplicate and delete buttons
- Full-width edit mode for better focus
- Toast notifications for all actions
- Keyboard shortcuts (Cmd/Ctrl+Enter to add/save, Esc to cancel)
- Removed old EdgeTypeForm in favor of modular components
Changes to actor type configuration:
- Updated TypeManagementList to match EdgeTypeManagementList styling
- White background cards with click-to-edit
- Always-visible action buttons (no hover-to-reveal)
- Simplified implementation (removed complex menu states)
- Consistent appearance across both type configurations
New components:
- EdgeTypeFormFields: Reusable form with compact layout
- EditEdgeTypeInline: Inline editing component
- QuickAddEdgeTypeForm: Quick add interface
- EdgeTypeManagementList: Scrollable list with actions
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Consolidates name, color, and icon fields into a single horizontal row
for more compact form layout. Removes progressive disclosure pattern to
show all fields at once.
Changes:
- Single-row layout for name, color, and icon fields with proper alignment
- Name field uses flex-1 with min-w-0 for proper text truncation
- Color picker fixed at h-8 to match input heights
- Icon popover uses fixed positioning (z-9999) to prevent clipping
- All form fields now always visible (removed collapsible advanced options)
- Removed edit panel header for cleaner UI
- Removed border above action buttons
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implements configurable shape variants for actor nodes, allowing visual
differentiation of node types beyond just color.
Features:
- Five shape options: rectangle, circle, rounded rectangle, ellipse, pill
- All shapes use pure CSS (border-radius) for consistent behavior
- Auto-grow with content
- Perfect shadow and selection/highlight effects
- Proper React Flow handle alignment
- Shape selector UI with visual previews
- Migration logic for existing documents (defaults to rectangle)
Shape characteristics:
- Rectangle: Standard, general purpose
- Circle: Round, for people and concepts
- Rounded Rectangle: Soft edges, friendly appearance
- Ellipse: Oval/horizontal, for processes and stages
- Pill: Capsule, compact for tags and labels
Technical approach:
- Uses border-radius for all shapes (no clip-path)
- Ensures boxShadow follows shape contours properly
- Each shape component maintains consistent props interface
- NodeShapeRenderer routes to appropriate shape component
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Creates a new extendable settings store for application-wide preferences
that persist across browser sessions using Zustand's persist middleware.
Architecture:
- New settingsStore.ts using Zustand persist middleware
- Automatic localStorage synchronization
- Versioned schema (v1) for future migrations
- Clean, typed interface for easy extensibility
Changes:
- Created settingsStore for persistent global settings
- Migrated autoZoomEnabled from searchStore to settingsStore
- Updated GraphEditor to use settings store for auto-zoom
- Updated LeftPanel to use settings store for toggle control
- searchStore now focuses on ephemeral filter/search state
Settings Persistence:
- Storage key: 'constellation-settings'
- Automatically saves on any setting change
- Restores settings on page reload
- Same proven pattern as panelStore
Future Extensibility:
The settings store is designed to easily accommodate new settings:
- Theme preferences (light/dark mode)
- Default view options
- User interface preferences
- Any application-wide persistent settings
Benefits:
- User preferences persist across sessions
- Clean separation between ephemeral and persistent state
- Type-safe settings management
- Easy to extend for future features
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implements automatic viewport adjustment to focus on filtered nodes when
search or filter criteria change, providing immediate visual feedback.
Features:
- Auto-zoom triggers when search text or type filters are applied
- 300ms debouncing prevents excessive zooming while typing
- Only zooms when some (but not all) nodes match filters
- Smooth 300ms animation with 20% padding and 2.5x max zoom
- Toggle control via compact icon button in search header
- Enabled by default, persists user preference in search store
UI Changes:
- Added CenterFocusStrong icon toggle in LeftPanel search header
- Icon is blue when enabled, gray when disabled
- Tooltip shows current state
- Positioned after "Reset filters" button
Implementation:
- Search store tracks autoZoomEnabled state
- GraphEditor monitors filter changes and calculates matching nodes
- Uses React Flow's fitView() with smart node filtering
- Skips zoom when disabled, no nodes, or no active filters
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Extends the search and filter system to include edge/relation searching
alongside the existing actor search functionality.
Changes:
- Search input now searches both actors AND relations
- Edges are filtered by custom label or relation type name
- Updated placeholder text to "Search actors and relations..."
- Results summary now shows separate counts for actors and relations
- Non-matching edges are dimmed to 20% opacity when filters are active
- Search logic applies consistently across CustomEdge and LeftPanel
The same search text field is used for both actors and relations,
providing a unified search experience across the entire graph.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Removes the Ctrl+A keyboard shortcut and associated select-all functionality
that was not working properly.
Changes:
- Remove select-all shortcut definition from useGlobalShortcuts
- Remove "Select All" menu item from View menu
- Remove handleSelectAll stub function from App.tsx
- Clean up onSelectAll prop from MenuBar component
The select-all feature was dysfunctional (only logging to console) and
not properly implemented, so it has been removed entirely.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Removes the upper toolbar and consolidates undo/redo controls into the
Edit menu for a cleaner interface with more screen space.
Changes:
- Move undo/redo buttons from Toolbar to Edit menu with descriptions
- Remove Toolbar component from App layout
- Implement closeAllMenus event system for coordinated menu management
- Add event listeners to close menus when clicking on graph/timeline canvas
- Add cross-menu closing: context menus close menu bar and vice versa
- Fix React warning by deferring event dispatch with setTimeout
Benefits:
- Cleaner UI with more vertical space for graph editor
- Unified menu system prevents multiple menus open simultaneously
- Context menus and menu bar dropdowns coordinate properly
- Consistent UX: clicking anywhere closes open menus
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Creates reusable ConnectionDisplay component and enhances connection
visualization in both Actor and Relation properties panels.
Changes:
- Add ConnectionDisplay component for consistent connection visualization
- Shows source and target actors with icons, labels, and type names
- Includes direction indicators (→, ↔, —) based on directionality
- Provides tooltips with node IDs on hover
- Enhance Actor Properties connections section
- Display full actor information instead of just node IDs
- Show edge type badges with color indicators
- Include custom labels when different from type labels
- Use ConnectionDisplay component for rich connection details
- Refactor Relation Properties to use ConnectionDisplay
- Eliminates duplicate connection rendering code
- Maintains consistent UI across panels
- Change actor type updates to apply instantly
- Remove debounce delay for actor type dropdown changes
- Provides immediate visual feedback when changing types
- Consistent with relation type and directionality behavior
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implements search and filter feature from UX_ANALYSIS.md to help users
find actors and relations in complex graphs.
Features:
- Search store with Zustand for managing search/filter state
- Real-time search by actor label, description, or type name
- Filter by actor types (show/hide specific node types)
- Filter by relation types (show/hide specific edge types)
- Visual feedback: non-matching items dimmed to 20% opacity
- Matching items highlighted with colored glow when filters active
- Results counter showing X actors of Y total
- Ctrl+F keyboard shortcut to focus search input
- Expands left panel if collapsed
- Opens search section if closed
- Focuses search input field
UI improvements:
- Search input with magnifying glass icon and clear button
- Reset filters link (only visible when filters active)
- Checkboxes for each actor/relation type with visual indicators
- Smooth transitions and hover states
- Fixed icon overlap issue in search input
Components modified:
- CustomNode: Apply opacity/highlighting based on search matches
- CustomEdge: Apply opacity based on relation type filters
- LeftPanel: Full search UI with filters in existing section
- App: Wire up Ctrl+F shortcut with ref-based focus handler
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Increase collapsed bottom panel height from 40px to 48px for better proportions
- Show current state indicator in bottom panel even when collapsed
- Remove unnecessary and broken close button from right panel header
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Removes duplicate confirmation dialogs when deleting documents.
Previously, users were asked twice: once by the UI component's custom
dialog and again by window.confirm in the store.
Changes:
- Remove window.confirm from workspaceStore deleteDocument function
- Add useConfirm hook to DocumentTabs component for delete action
- Consistent confirmation UX across DocumentManager and DocumentTabs
Both components now show the same styled confirmation dialog with
proper handling of unsaved changes warnings.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implements a comprehensive timeline system that enables documents to contain
multiple constellation states with branching timelines. This allows users to
create different versions of their analysis for temporal evolution, alternative
scenarios, or what-if analysis.
Core Features:
- Timeline store managing multiple states per document with branching structure
- Visual timeline panel with React Flow-based state graph visualization
- State management: create, switch, rename, duplicate (parallel/series), delete
- Per-state undo/redo history (max 50 actions per state)
- Context menu for timeline node operations
- Collapsible timeline panel (always visible, moved toolbar to panel header)
Architecture Changes:
- Document structure: removed top-level graph field, states now only in timeline
- Global types: nodeTypes and edgeTypes are now global per document, not per state
- State graphs: only contain nodes and edges, types inherited from document
- Persistence: full timeline serialization/deserialization with all states
- History system: converted from document-level to per-state independent stacks
Timeline Components:
- TimelineView: main timeline visualization with state nodes and edges
- BottomPanel: collapsible container with timeline controls in header
- StateNode: custom node component showing state info and active indicator
- CreateStateDialog: dialog for creating new timeline states
- RenameStateDialog: dialog for renaming existing states
- Context menu: right-click operations (rename, duplicate parallel/series, delete)
Document Management:
- Documents always have timeline (initialized with root state on creation)
- Timeline persisted with document in localStorage
- Export/import includes complete timeline with all states
- Migration support for legacy single-state documents
Store Updates:
- timelineStore: manages timelines, states, and timeline operations
- historyStore: per-state history with independent undo/redo stacks
- workspaceStore: saves/loads timeline data, handles global types
- panelStore: added timeline panel visibility state
- useActiveDocument: syncs timeline state with graph editor
Context Menu Improvements:
- Smart viewport edge detection to prevent overflow
- Click-outside detection for React Flow panes
- Consistent styling across application
Files Added:
- src/types/timeline.ts - Timeline type definitions
- src/stores/timelineStore.ts - Timeline state management
- src/components/Timeline/TimelineView.tsx - Main timeline component
- src/components/Timeline/BottomPanel.tsx - Timeline panel container
- src/components/Timeline/StateNode.tsx - State node visualization
- src/components/Timeline/CreateStateDialog.tsx - State creation dialog
- src/components/Timeline/RenameStateDialog.tsx - State rename dialog
Files Removed:
- src/stores/persistence/middleware.ts - Obsolete persistence middleware
Documentation:
- Added comprehensive timeline feature documentation
- Implementation checklists and quick reference guides
- Temporal analysis concepts and UX guidelines
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Fixed TypeScript build errors by replacing invalid `style` prop with
proper Material-UI icon props. Icon components only accept `fontSize`
and `className` props, not arbitrary style objects.
Changes:
- Move fontSize styling to wrapping div elements
- Use proper `fontSize="small"` prop on icon components
- Apply color styling to container div (unchanged)
This resolves two TypeScript errors at lines 565 and 597 where
`style={{ fontSize: '14px' }}` was incorrectly passed to MUI icons.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Improvements to the relation properties panel:
1. Show actor labels instead of IDs in connection display
- Display actor icons with type-specific colors
- Show actor labels and type names (e.g., "Person", "Organization")
- IDs available on hover via tooltips
- Layout: [icon] Label (Type) → (Type) Label [icon]
2. Make relation type changes instant
- Relation type dropdown now applies changes immediately
- No more 500ms delay or "Saving changes..." message
- Provides instant visual feedback like directionality toggles
3. Fix connection display updates
- Connection info now reads current edge data from store
- Source/target actors update immediately when reversing direction
- Direction arrow updates immediately when changing directionality
- Panel properly reflects all edge changes in real-time
Only the custom label text input retains debounced saves to avoid
excessive updates while typing.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Removes the 500ms debounce delay when changing edge directionality
in the right panel. Directionality toggle buttons now apply changes
immediately, providing instant visual feedback.
Text fields (relation type and custom label) still use debounced
saves to avoid excessive updates while typing.
Improves UX by making toggle interactions feel more responsive.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Adds quick access to configuration modals from the left panel:
- Settings icon (⚙️) next to "Add Actors" section opens Actor Type config
- Settings icon next to "Relations" section opens Relation Type config
- Icons positioned between section title and expand/collapse chevron
- Tooltips provide clear indication of functionality
This provides convenient access to type configuration without needing
to navigate through the menu bar, improving workflow efficiency.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implements a user-friendly dialog that prompts for document names before
creating new documents, replacing the default "Untitled Analysis" behavior.
Features:
- InputDialog component for text input with validation
- useCreateDocument hook to centralize naming logic
- Pre-filled default value "Untitled Analysis"
- Validation to prevent empty document names
- Helpful placeholder text with examples
- Keyboard shortcuts (Enter/Escape)
- Auto-focus and select input field
Updated all document creation entry points:
- Menu Bar: "New Document" and "New from Template"
- Document Tabs: "+" button
- Document Manager: "New Document" button
- Empty State: "New Document" button
- Keyboard shortcut: Ctrl+N
This provides a consistent UX across the application and reduces code
duplication by using a single reusable hook.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Adds full support for directed, bidirectional, and undirected relationships
between actors with visual arrow markers and intuitive controls.
**Type System:**
- Add EdgeDirectionality type (directed | bidirectional | undirected)
- Add directionality field to RelationData
- Add defaultDirectionality field to EdgeTypeConfig
**Visual Representation:**
- Directed edges: single arrow marker at target (→)
- Bidirectional edges: arrow markers at both ends (↔)
- Undirected edges: no arrow markers (—)
- Separate marker definitions for start/end to ensure correct orientation
**Property Panel Controls:**
- MUI ToggleButtonGroup for selecting directionality
- Visual connection indicator with directional symbols
- Reverse direction button (swaps source/target, only for directed edges)
- Live updates with 500ms debounce
**Edge Type Configuration:**
- Default directionality selector in edge type form
- Dropdown with helpful descriptions (→, ↔, —)
- Applied to both create and edit workflows
**Edge Creation:**
- New edges inherit defaultDirectionality from edge type config
- Falls back to 'directed' for backwards compatibility
**Reverse Direction:**
- Swaps source/target and sourceHandle/targetHandle
- Maintains edge ID and selection state
- Tracked in undo/redo history
Includes comprehensive UX specification document with wireframes,
interaction patterns, accessibility guidelines, and implementation phases.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Adds overflow-hidden to GraphMetrics outer container to establish proper
scrolling context. Without it, the flex container doesn't constrain child
height, preventing scrollbar from appearing when metrics content exceeds
available space.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Removes Ctrl+B and Ctrl+I keyboard shortcuts that were causing panels
to disappear completely instead of collapsing properly. Also updates
all panel tooltips to no longer reference the removed shortcuts.
Changes:
- Removed Ctrl+B (left panel) and Ctrl+I (right panel) shortcut handlers
- Updated left panel tooltips: removed "(Ctrl+B)" references
- Updated right panel tooltips: removed "(Ctrl+I)" references
- Tooltips now simply show "Collapse Panel" / "Expand Panel"
- Escape key handler preserved for closing property panels
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Consolidates three duplicate header implementations in RightPanel into a
single reusable PanelHeader component, following DRY principles.
Changes:
- Created PanelHeader component in RightPanel.tsx with consistent props
- Refactored Actor Properties to use PanelHeader
- Refactored Relation Properties to use PanelHeader
- Refactored Graph Analysis to use PanelHeader (removed internal header)
- All panel headers now have consistent appearance and behavior
- Supports optional close button and required collapse functionality
Benefits:
- Eliminates code duplication across panel views
- Ensures consistent UX across all panel states
- Easier to maintain and update header behavior in one place
- Reduces bundle size by removing redundant JSX
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implements section 6.1 from UX_ANALYSIS.md - Graph Metrics and Analysis.
Transforms the empty "No Selection" state in the right panel into a
valuable analysis dashboard.
Features:
- Graph analysis utility with metric calculations:
- Actor/relation counts
- Graph density (connectivity ratio)
- Average connections per actor
- Most connected actors (top 5)
- Isolated actors count
- Connected components detection
- Breakdown by actor/relation type
- GraphMetrics component with sections:
- Overview: basic stats and density
- Most Connected Actors: ranked list
- Graph Structure: isolated nodes, components
- Type breakdowns: actors and relations by type
- Visual polish: icons, tooltips, hover states
- Warning highlights for isolated actors
- Info highlights for multiple components
- Integration:
- Replaces empty state in RightPanel
- Automatically updates when graph changes
- Memoized calculations for performance
- Consistent styling with existing panels
Now provides immediate analytical value when opening a document,
making the application live up to its "Analyzer" name.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implements toast notifications from UX_ANALYSIS.md to provide clear,
non-intrusive feedback for user actions.
Features:
- Toast store with Zustand for global state management
- Four toast variants: success, error, info, warning
- Auto-dismiss after configurable duration (default 4s)
- Max 3 visible toasts with FIFO queue
- Smart positioning that avoids right panel overlap
- Smooth slide-in/fade-out animations
Notifications added for:
- File operations (import/export success/errors)
- Document operations (create/delete/rename/duplicate)
- Workspace operations (import/export)
Toast container dynamically repositions based on right panel state
to ensure toasts never overlap with critical UI elements.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implemented image export functionality using html-to-image that actually
slaps. No more bloated screenshots with miles of blank space - this baby
wraps your graph tighter than shrink wrap on a fresh deck.
Features:
- PNG export with proper 300 DPI quality (4x pixelRatio)
- SVG vector export for infinite scaling
- Smart bounds calculation that hugs your nodes
- Configurable padding (default: 10px of breathing room)
- Accessible via File menu
Technical highlights:
- Direct transform calculation instead of getViewportForBounds bloat
- Proper pixelRatio handling (not that 16x scaling nonsense)
- Based on React Flow's official pattern but actually optimized
- Uses html-to-image@1.11.11 (newer versions are broken)
Export quality goes hard. Print-ready PNGs. Crisp. Clean. Chef's kiss.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
All keyboard shortcut labels in the MenuBar now come from the
centralized keyboard shortcut manager via the new useShortcutLabels
hook, eliminating hardcoded duplicates.
Changes:
- Add useShortcutLabels hook for retrieving formatted shortcut labels
- Update MenuBar to use dynamic shortcut labels from manager
- Platform-aware display (Cmd on Mac, Ctrl elsewhere)
- Shortcuts automatically update if changed in manager
- Fix MUI icon fontSize prop issue in LeftPanel
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>