Commit 027732b
ui: Enhance right panel UX with text selection, truncation, and search optimization (#72)
* feat: Add text truncation with read more/less functionality to right panels
Add expandable text containers with automatic truncation to improve readability
and prevent information overflow in right panel detail views.
Changes:
- Risk panel: Description, Mitigation Strategy, and Impact fields (200 char limit)
- Task panel: Description and Question to Ask fields (200 char limit)
- Lesson panel: Description and Recommendation fields (200 char limit)
- Blocker panel: Description field (200 char limit)
Features:
- Auto-truncates text at 200 characters with ellipsis
- Interactive "Read more"/"Read less" toggle with expand/collapse icons
- Maintains consistent styling with existing UI
- Supports placeholder text styling for empty values
- Stateful widget with lightweight state management
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* ui: Add subtle comment count badges to Updates tab in item detail panels
Add non-intrusive comment count indicators to the Updates tab across all item types (tasks, risks, blockers, lessons learned). The badge uses a neutral gray color scheme to avoid drawing excessive attention while providing useful at-a-glance information.
Key features:
- Subtle gray badge styling (surfaceContainerHighest) instead of bright primary color
- Badge only displays when comment count > 0 (hidden when no comments)
- Reactive updates via Riverpod itemUpdatesNotifierProvider
- Graceful handling of loading/error states (no badge shown)
- Consistent implementation across all detail panel types
- Filters only ItemUpdateType.comment from all updates
Modified files:
- ItemDetailPanel: Added commentCount parameter and neutral badge display
- TaskDetailPanel: Added comment count calculation logic
- RiskDetailPanel: Added comment count calculation logic
- BlockerDetailPanel: Added comment count calculation logic
- LessonLearnedDetailPanel: Added comment count calculation logic
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* ui: Fix project name truncation across risks, tasks, and lessons views
Remove artificial width constraints on project name badges to allow better use of available horizontal space.
Changes:
- Risks compact view: Replace ConstrainedBox(maxWidth: 100) with Flexible widget
- Risks kanban: Simplify severity badge to icon-only + expand project badge to use remaining space
- Tasks kanban: Simplify priority badge to icon-only + expand project badge to use remaining space
- Lessons compact: Replace ConstrainedBox(maxWidth: 100) with Flexible widget
Project names now display more fully before truncating, improving readability while maintaining responsive layout behavior.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* ui: Enable text selection and copying across all detail panels
Replace Text widgets with SelectableText for user-generated content
throughout the application, enabling users to select and copy text
in all detail views and summary pages.
Changes:
- Task detail panel: descriptions, blocker descriptions, questions
- Risk detail panel: descriptions, mitigation strategies, assignments
- Blocker detail panel: descriptions, resolutions, dependencies
- Lesson learned panel: descriptions, recommendations, context, tags
- Item updates tab: all comments and update content
- Summary widgets: risks, blockers, action items, decisions, questions
UI labels, badges, and structural elements remain as Text widgets
to maintain proper visual hierarchy and interaction patterns.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* fix: Resolve async event loop blocking in hybrid search diversity optimization
## Problem
Risk item queries with rich context were hanging indefinitely during the
diversity optimization stage of hybrid search. The issue occurred when processing
26+ search results, blocking the entire application.
## Root Causes
1. **Blocking synchronous operations in async functions**: `sentence_transformer.encode()`
is a CPU-intensive synchronous call that was blocking the async event loop
2. **Complex O(n²) MMR algorithm**: The Maximal Marginal Relevance diversity
selection had nested loops causing excessive computation time
## Solution
Applied a two-part fix:
### Part 1: Async Threading for Blocking Operations
- Changed `sentence_transformer.encode()` to `await asyncio.to_thread()`
- Applied in both `_diversify_results()` and `_calculate_diversity_score()`
- Runs CPU-intensive operations in a thread pool, preventing event loop blocking
### Part 2: Simplified Diversity Algorithm
- Replaced O(n²) MMR with O(n) greedy filtering approach
- Keeps best result, filters out results with >0.85 similarity
- Much faster while maintaining good diversity filtering
## Frontend Enhancement
- Added text selection capability to Ask AI panel using `SelectableText`
- Users can now copy questions and responses from the AI chat
## Testing
Added focused integration tests to prevent regression:
- `test_diversify_results_with_async_threading`: Verifies 26 results complete without hanging
- `test_calculate_diversity_score_with_async_threading`: Confirms async threading in score calculation
- Both tests use `asyncio.wait_for()` with timeouts to detect blocking
## Impact
- Risk item queries now complete in ~2-5 seconds (previously hung indefinitely)
- Hybrid search completed in 2,164ms with 15 final results and 0.80 diversity score
- All RAG pipeline stages now complete successfully
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* refactor: Extract duplicated ExpandableTextContainer widget and optimize backend performance
Critical fixes addressing code review feedback:
Frontend:
- Extract _ExpandableTextContainer to shared widget (lib/shared/widgets/expandable_text_container.dart)
- Remove ~300 lines of duplicated code across 4 files
- Add input validation for empty strings and extremely long strings (>100k chars)
- Add showAsPlaceholder parameter for optional placeholder styling
- Update all references in lesson_learned_detail_panel, blocker_detail_panel, risk_detail_panel, and task_detail_panel
- Add comprehensive widget tests with 8 test cases
Backend:
- Fix O(n³) performance issue in hybrid_search.py diversity optimization
- Replace list.index() calls with dict-based index mapping (O(n²) complexity)
- Improves search response times for large result sets
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Co-authored-by: nkondratyk93 <nkondratyk93@users.noreply.github.com>
* refactor: Fix code review issues - performance, null safety, and DRY improvements
High Priority Fixes:
- Fix performance concern in hybrid_search.py diversity algorithm
- Remove risky id() dictionary mapping that could cause incorrect lookups
- Use direct index tracking instead (O(n²) remains, but safer)
- Extract magic number 0.85 to diversity_similarity_threshold config parameter
Medium Priority Fixes:
- Fix null safety in task_detail_panel.dart
- Replace null assertions (!.) with null-aware operators (?.)
- Add explicit null checks before accessing nested properties
- Extract duplicated AI assist button code to reusable widget
- Create AIAssistButton widget in lib/shared/widgets/
- Update 4 detail panel files to use the new widget
- Reduce code duplication by ~80 lines
- Replace hardcoded green colors with theme colors
- Update AIAssistButton to use theme.colorScheme.primary by default
- Update risk_detail_panel.dart to use theme colors
Co-authored-by: nkondratyk93 <nkondratyk93@users.noreply.github.com>
* test: Add comprehensive widget tests for AIAssistButton
feat: Add error handling for AI assist dialogs across all detail panels
perf: Optimize comment count computation with Riverpod select
- Add 9 comprehensive widget tests for AIAssistButton component
- Wrap AI assist dialog calls in try-catch blocks with user-friendly error messages
- Use Riverpod .select() to only rebuild when comment count changes, not on any update
- Prevents unnecessary rebuilds and improves performance in detail panels
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: nkondratyk93 <nkondratyk93@users.noreply.github.com>
* test: Fix compilation errors in expandable_text_container_test.dart
- Change const to final for longText variables using string multiplication
- Fix 3 compilation errors (const_eval_type_num) on lines 37, 48, 64
- Update extreme length truncation test to properly verify behavior
- All 8 tests now passing with no analyzer issues
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* test: Fix risk kanban card severity badge tests
The widget displays severity badges with colored flag icons, not text labels.
Updated tests to verify icon colors instead of looking for text labels.
Changes:
- Replace text label expectations with icon color verification
- Test critical (red), high (red.shade400), medium (orange), low (green)
- Remove unused flutter_riverpod import
- All 20 tests now passing with no analyzer issues
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* feat: Add context_id to conversations for context-specific filtering
Add context_id column to conversations table to enable filtering conversations by context (e.g., risk items, tasks). This allows each context to maintain separate conversation histories.
Backend changes:
- Add context_id column to Conversation model (nullable)
- Add database migration to create context_id column with index
- Update conversations router to support context_id filtering in GET requests
- Update conversation create/update endpoints to handle context_id
- Refactor query building to use dynamic conditions
Frontend changes:
- Update API client to support context_id query parameter
- Update query provider to pass context_id when fetching conversations
- Update mock API client with context_id support
This enables separate conversation histories for:
- Organization-level (project_id = NULL, context_id = NULL)
- Project-level (project_id = <uuid>, context_id = NULL)
- Context-specific (project_id = <uuid>, context_id = 'risk_<uuid>')
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: nikolay.k <77578004+the-harpia-io@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: nkondratyk93 <nkondratyk93@users.noreply.github.com>1 parent c0e1998 commit 027732b
28 files changed
Lines changed: 1331 additions & 320 deletions
File tree
- backend
- alembic/versions
- models
- routers
- services/rag
- tests/integration
- lib
- core/network
- features
- lessons_learned/presentation/widgets
- projects/presentation/widgets
- queries/presentation
- providers
- widgets
- risks/presentation/widgets
- summaries/presentation/widgets
- tasks/presentation/widgets
- test
- features/risks/presentation/widgets
- mocks
Lines changed: 41 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
17 | 17 | | |
18 | 18 | | |
19 | 19 | | |
| 20 | + | |
20 | 21 | | |
21 | 22 | | |
22 | 23 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
32 | 32 | | |
33 | 33 | | |
34 | 34 | | |
| 35 | + | |
35 | 36 | | |
36 | 37 | | |
37 | 38 | | |
38 | 39 | | |
39 | 40 | | |
| 41 | + | |
40 | 42 | | |
41 | 43 | | |
42 | 44 | | |
| |||
51 | 53 | | |
52 | 54 | | |
53 | 55 | | |
| 56 | + | |
54 | 57 | | |
55 | 58 | | |
56 | 59 | | |
| |||
61 | 64 | | |
62 | 65 | | |
63 | 66 | | |
| 67 | + | |
64 | 68 | | |
65 | 69 | | |
66 | 70 | | |
67 | 71 | | |
68 | 72 | | |
69 | | - | |
| 73 | + | |
70 | 74 | | |
71 | 75 | | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
72 | 79 | | |
73 | 80 | | |
74 | | - | |
75 | | - | |
76 | | - | |
77 | | - | |
78 | | - | |
79 | | - | |
80 | | - | |
81 | | - | |
82 | | - | |
83 | | - | |
| 81 | + | |
84 | 82 | | |
85 | | - | |
86 | | - | |
87 | | - | |
88 | | - | |
89 | | - | |
90 | | - | |
91 | | - | |
92 | | - | |
93 | | - | |
94 | | - | |
95 | | - | |
96 | | - | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
97 | 94 | | |
98 | 95 | | |
99 | 96 | | |
| |||
142 | 139 | | |
143 | 140 | | |
144 | 141 | | |
| 142 | + | |
145 | 143 | | |
146 | 144 | | |
147 | 145 | | |
| |||
231 | 229 | | |
232 | 230 | | |
233 | 231 | | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
234 | 235 | | |
235 | 236 | | |
236 | 237 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
78 | 78 | | |
79 | 79 | | |
80 | 80 | | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
81 | 84 | | |
82 | 85 | | |
83 | 86 | | |
| |||
225 | 228 | | |
226 | 229 | | |
227 | 230 | | |
| 231 | + | |
228 | 232 | | |
229 | 233 | | |
230 | 234 | | |
| |||
236 | 240 | | |
237 | 241 | | |
238 | 242 | | |
239 | | - | |
| 243 | + | |
240 | 244 | | |
241 | 245 | | |
242 | 246 | | |
| |||
786 | 790 | | |
787 | 791 | | |
788 | 792 | | |
789 | | - | |
790 | | - | |
| 793 | + | |
| 794 | + | |
791 | 795 | | |
792 | 796 | | |
793 | 797 | | |
794 | 798 | | |
795 | 799 | | |
796 | | - | |
| 800 | + | |
797 | 801 | | |
798 | 802 | | |
799 | 803 | | |
800 | 804 | | |
801 | 805 | | |
802 | | - | |
803 | | - | |
804 | | - | |
805 | | - | |
806 | | - | |
807 | | - | |
808 | | - | |
809 | | - | |
810 | | - | |
811 | | - | |
812 | | - | |
813 | | - | |
814 | | - | |
815 | | - | |
816 | | - | |
817 | | - | |
818 | | - | |
819 | | - | |
820 | | - | |
821 | | - | |
822 | | - | |
823 | | - | |
824 | | - | |
825 | | - | |
826 | | - | |
827 | | - | |
828 | | - | |
829 | | - | |
830 | | - | |
831 | | - | |
832 | | - | |
833 | | - | |
834 | | - | |
835 | | - | |
836 | | - | |
837 | | - | |
838 | | - | |
839 | | - | |
840 | | - | |
841 | | - | |
842 | | - | |
843 | | - | |
844 | | - | |
| 806 | + | |
| 807 | + | |
| 808 | + | |
| 809 | + | |
| 810 | + | |
| 811 | + | |
| 812 | + | |
| 813 | + | |
| 814 | + | |
| 815 | + | |
| 816 | + | |
| 817 | + | |
| 818 | + | |
| 819 | + | |
| 820 | + | |
| 821 | + | |
| 822 | + | |
| 823 | + | |
| 824 | + | |
| 825 | + | |
| 826 | + | |
| 827 | + | |
| 828 | + | |
845 | 829 | | |
846 | 830 | | |
847 | 831 | | |
| |||
862 | 846 | | |
863 | 847 | | |
864 | 848 | | |
865 | | - | |
| 849 | + | |
866 | 850 | | |
867 | 851 | | |
868 | 852 | | |
869 | | - | |
| 853 | + | |
870 | 854 | | |
871 | 855 | | |
872 | 856 | | |
873 | 857 | | |
874 | | - | |
| 858 | + | |
875 | 859 | | |
876 | | - | |
| 860 | + | |
877 | 861 | | |
878 | 862 | | |
879 | 863 | | |
880 | 864 | | |
881 | 865 | | |
882 | | - | |
| 866 | + | |
| 867 | + | |
883 | 868 | | |
884 | 869 | | |
885 | 870 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1056 | 1056 | | |
1057 | 1057 | | |
1058 | 1058 | | |
| 1059 | + | |
| 1060 | + | |
| 1061 | + | |
| 1062 | + | |
| 1063 | + | |
| 1064 | + | |
| 1065 | + | |
| 1066 | + | |
| 1067 | + | |
| 1068 | + | |
| 1069 | + | |
| 1070 | + | |
| 1071 | + | |
| 1072 | + | |
| 1073 | + | |
| 1074 | + | |
| 1075 | + | |
| 1076 | + | |
| 1077 | + | |
| 1078 | + | |
| 1079 | + | |
| 1080 | + | |
| 1081 | + | |
| 1082 | + | |
| 1083 | + | |
| 1084 | + | |
| 1085 | + | |
| 1086 | + | |
| 1087 | + | |
| 1088 | + | |
| 1089 | + | |
| 1090 | + | |
| 1091 | + | |
| 1092 | + | |
| 1093 | + | |
| 1094 | + | |
| 1095 | + | |
| 1096 | + | |
| 1097 | + | |
| 1098 | + | |
| 1099 | + | |
| 1100 | + | |
| 1101 | + | |
| 1102 | + | |
| 1103 | + | |
| 1104 | + | |
| 1105 | + | |
| 1106 | + | |
| 1107 | + | |
| 1108 | + | |
| 1109 | + | |
| 1110 | + | |
| 1111 | + | |
| 1112 | + | |
| 1113 | + | |
| 1114 | + | |
| 1115 | + | |
| 1116 | + | |
| 1117 | + | |
| 1118 | + | |
| 1119 | + | |
| 1120 | + | |
| 1121 | + | |
| 1122 | + | |
| 1123 | + | |
| 1124 | + | |
| 1125 | + | |
| 1126 | + | |
| 1127 | + | |
| 1128 | + | |
| 1129 | + | |
| 1130 | + | |
| 1131 | + | |
| 1132 | + | |
| 1133 | + | |
| 1134 | + | |
| 1135 | + | |
| 1136 | + | |
| 1137 | + | |
| 1138 | + | |
| 1139 | + | |
| 1140 | + | |
| 1141 | + | |
| 1142 | + | |
| 1143 | + | |
| 1144 | + | |
| 1145 | + | |
| 1146 | + | |
| 1147 | + | |
| 1148 | + | |
| 1149 | + | |
| 1150 | + | |
| 1151 | + | |
| 1152 | + | |
| 1153 | + | |
| 1154 | + | |
| 1155 | + | |
0 commit comments