Commit graph

13 commits

Author SHA1 Message Date
Jan-Henrik Bruhn
c9c888d0ac Implement whole-node easy-connect handle system with floating edges
Migrated from 4-position handle system (top/right/bottom/left) to React Flow's
easy-connect pattern where the entire node surface is connectable and edges
dynamically route to the nearest point on the node border.

Key changes:
- Migration utility removes old 4-position handle references for backwards compatibility
- Full-coverage invisible handles on CustomNode and GroupNode (maximized state)
- Floating edges use node.measured dimensions and node.internals.positionAbsolute
- useInternalNode hook for correct absolute positioning of nodes in groups
- All edges now omit handle fields, allowing dynamic border calculations

This improves UX by making nodes easier to connect (whole surface vs tiny handles)
and edges intelligently route to optimal connection points.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-24 13:01:04 +01:00
Jan-Henrik Bruhn
3e2a7b6b20 Add multi-filter tangible support with presentation mode filtering
Features:
- Extended tangible filters to support labels, actor types, and relation types
- Added configurable combine mode (OR/AND) for filter logic
- Separated presentation mode filters from editing mode filters
- Implemented backward compatibility with legacy filterLabels format

Filter Behavior:
- OR mode (default for tangibles): Show items matching ANY filter category
- AND mode (default for editing): Show items matching ALL filter categories
- Presentation mode uses tuioStore.presentationFilters
- Editing mode uses searchStore filters

UI Improvements:
- Replaced radio buttons with horizontal button layout for mode selection
- Replaced dropdown with horizontal buttons for combine mode selection
- Consolidated Name and Hardware ID fields into two-column layout
- More compact and consistent interface

Technical Changes:
- Added FilterConfig type with combineMode field
- Created tangibleMigration.ts for backward compatibility
- Created tangibleValidation.ts for multi-format validation
- Added useActiveFilters hook for mode-aware filter access
- Added nodeMatchesFilters and edgeMatchesFilters helper functions
- Updated cascade cleanup for node/edge type deletions
- Removed all TUIO debug logging

Tests:
- Added 44 comprehensive tests for useActiveFilters hook
- Added tests for tangibleMigration utility
- All 499 tests passing

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-19 20:20:34 +01:00
Jan-Henrik Bruhn
8dcca18008 add tangible configuration interface and internal model for tangible configuration 2026-01-16 09:50:10 +01:00
Jan-Henrik Bruhn
7c49ad0baa feat: render edges between minimized groups with floating edges
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>
2025-10-21 11:28:48 +02:00
Jan-Henrik Bruhn
3b7497ec99 feat: add multi-select properties panel with bulk operations
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>
2025-10-21 10:57:07 +02:00
Jan-Henrik Bruhn
0ac15353ae refactor: remove legacy persistence code and migration system (Phase 1)
Removes ~350 lines of legacy code from single-document system.

Changes:
- Delete src/stores/persistence/loader.ts (legacy load functions)
- Delete src/stores/persistence/saver.ts (legacy save functions)
- Delete src/stores/workspace/migration.ts (no migration support needed)
- Create src/stores/workspace/documentUtils.ts (consolidated utilities)

Extracted and consolidated:
- validateDocument() - document structure validation
- getCurrentGraphFromDocument() - extract current graph from timeline
- deserializeGraphState() - convert storage to runtime format
- serializeActors/Relations/Groups() - convert runtime to storage format
- createDocument() - create new document with initial timeline state

Updated imports:
- workspaceStore.ts: use documentUtils instead of loader/saver
- useActiveDocument.ts: use documentUtils.getCurrentGraphFromDocument
- fileIO.ts: use documentUtils for serialization/validation
- persistence.ts: use documentUtils.validateDocument
- graphStore.ts: remove legacy loadGraphState, start with empty state

Removed legacy storage keys:
- LEGACY_GRAPH_STATE from workspace/persistence.ts
- hasLegacyData() function (no longer needed)
- References to LEGACY_GRAPH_STATE in cleanupStorage.ts

Impact:
- No breaking changes for existing users (workspace format unchanged)
- Cleaner code organization (all document utils in one place)
- No migration support (old documents will not be loaded)
- Reduced technical debt (~350 lines removed)

Related: Phase 1 of STATE_MANAGEMENT_REFACTORING_PLAN.md

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 12:15:25 +02:00
Jan-Henrik Bruhn
b1e634d3c4 feat: add group minimize/maximize with floating edges and React Flow v12
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>
2025-10-20 11:52:44 +02:00
Jan-Henrik Bruhn
f5adbc8ead feat: add resizable actor grouping with full undo/redo support
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>
2025-10-18 20:06:59 +02:00
Jan-Henrik Bruhn
d98acf963b feat: implement label system and redesign filtering with positive filters
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>
2025-10-17 10:40:00 +02:00
Jan-Henrik Bruhn
e0784ff3d8 feat: add node shape variants with five distinct shapes
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>
2025-10-16 15:34:24 +02:00
Jan-Henrik Bruhn
aa2bd7e5d7 fix: preserve timeline states in document import/export
Fixed critical bug where importing a document would lose all timeline
states except the current one. Also cleaned up unused legacy persistence
functions.

Changes:
- Import now preserves complete document structure with all timeline states
- Export already worked correctly, serializing all timeline states
- Updated fileIO to return full ConstellationDocument instead of just graph
- Removed unused legacy functions: hasSavedState, getLastSavedTimestamp, clearSavedState
- Removed unused graphStore export/import (replaced by workspace-level system)
- Updated type definitions to reflect removed functions

The import process now correctly:
1. Accepts full ConstellationDocument from imported JSON
2. Preserves all timeline states and relationships
3. Loads complete timeline into timelineStore
4. Maintains document title and metadata

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-12 11:11:32 +02:00
Jan-Henrik Bruhn
28f8224284 feat: add timeline system for multi-state constellation analysis
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>
2025-10-11 22:00:34 +02:00
Jan-Henrik Bruhn
f56f928dcf Initial commit 2025-10-10 11:15:51 +02:00