Commit graph

18 commits

Author SHA1 Message Date
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
084a3bb486 feat: implement global settings system with localStorage persistence
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>
2025-10-16 14:30:49 +02:00
Jan-Henrik Bruhn
58e04650c0 feat: add auto-zoom to filtered search results
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>
2025-10-16 14:26:34 +02:00
Jan-Henrik Bruhn
f9c208d7ac feat: add edge search functionality to filter section
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>
2025-10-16 14:19:58 +02:00
Jan-Henrik Bruhn
89117415ed refactor: establish document as source of truth for node/edge types
Refactors the type management system to properly follow the
Workspace→Document→Timeline→Graph hierarchy, where nodeTypes and
edgeTypes are owned by the document rather than being independent
state in graphStore.

Changes:
- Add type management actions to workspaceStore (document-level)
- Update workspaceStore.saveDocument to stop copying types from graphStore
- Modify useActiveDocument to only track node/edge changes for dirty state
- Update useGraphWithHistory to route type operations through workspaceStore
- Update useDocumentHistory to read/restore types from document

Architecture:
- Document: Source of truth for types (persistent storage)
- graphStore: Synchronized working memory (optimized for React Flow)
- useActiveDocument: Bridge that syncs document → graphStore
- Type mutations: Always go through workspaceStore, then sync to graphStore

This ensures proper data ownership while maintaining graphStore as a
performance optimization layer for the UI.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-12 14:27:57 +02:00
Jan-Henrik Bruhn
1646cfb0ce feat: add search and filter functionality with Ctrl+F shortcut
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>
2025-10-12 12:11:29 +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
d775cb8863 refactor: migrate undo/redo from per-state to per-document level
Refactors the history system to track complete document state instead of
individual timeline states, making timeline operations fully undoable.

BREAKING CHANGE: History is now per-document instead of per-timeline-state.
Existing undo/redo stacks will be cleared on first load with this change.

Changes:
- historyStore: Track complete document snapshots (timeline + all states + types)
- useDocumentHistory: Simplified to work with document-level operations
- timelineStore: All timeline operations now record history
  - createState, switchToState, deleteState, updateState, duplicateState
- Fixed redo button bug (was mutating Zustand state directly)

New capabilities:
- Undo/redo timeline state creation
- Undo/redo timeline state deletion
- Undo/redo switching between timeline states
- Undo/redo renaming timeline states
- Unified history for all document operations

Technical improvements:
- Proper Zustand state management (no direct mutations)
- Document snapshots include entire timeline structure
- History methods accept currentSnapshot parameter
- Removed TypeScript 'any' types for better type safety

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-11 22:38:23 +02:00
Jan-Henrik Bruhn
227b61b2a0 fix: improve bottom panel collapsed state and remove broken right panel close button
- 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>
2025-10-11 22:22:42 +02:00
Jan-Henrik Bruhn
94c7845ca7 refactor: replace redundant window.confirm with custom dialog
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>
2025-10-11 22:08:00 +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
8998061262 feat: add toast notification system for visual feedback
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>
2025-10-10 23:13:28 +02:00
Jan-Henrik Bruhn
e7ff53dcd7 feat: side panels for properties and tools 2025-10-10 18:13:18 +02:00
Jan-Henrik Bruhn
09b62c69bd fix: clear graph editor when no document is active
Fixes an issue where nodes from a previous document would persist when
creating a new document after closing all documents.

The problem occurred because:
1. When all documents were closed (activeDocumentId becomes null), the
   graph store wasn't being cleared
2. When a new document was created, stale data from the old document
   could contaminate the new document through race conditions

Changes:
- Clear nodes and edges from graph store when activeDocumentId is null
- Add safeguard to prevent saving stale graph data to newly created
  documents before they've been fully loaded
- Maintain proper state tracking to prevent cross-document contamination

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-10 16:54:40 +02:00
Jan-Henrik Bruhn
99ab514c0c fix: prevent cross-document state contamination in useActiveDocument
Added lastSyncedStateRef to track the graph state that was last loaded/synced
for each document. This prevents stale comparisons when switching between
documents by ensuring dirty checks only run against the correct document's
state.

Changes:
- Track last synced state (nodes, edges, nodeTypes, edgeTypes) per document
- Skip dirty check if graph state belongs to a different document
- Compare current graph state against last synced state instead of active document
- Update last synced state reference when loading or saving changes

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-10 16:50:26 +02:00
Jan-Henrik Bruhn
79bfd525dd fix: remove unused variable 2025-10-10 11:35:57 +02:00
Jan-Henrik Bruhn
f56f928dcf Initial commit 2025-10-10 11:15:51 +02:00