Skip to content

Commit 2ed6d07

Browse files
authored
Merge pull request #39 from b-rodrigues/copilot/add-conflict-detection-visualization
Add conflict detection and tabbed diff view for overlapping patch edits
2 parents 4fd0a32 + da9bce2 commit 2ed6d07

File tree

8 files changed

+1372
-24
lines changed

8 files changed

+1372
-24
lines changed

CONFLICT_DETECTION.md

Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
# Conflict Detection and Visualization Feature
2+
3+
## Overview
4+
5+
This feature automatically detects conflicts between patches that modify the same text regions and provides visual indicators and tabbed comparison views to help users resolve conflicts.
6+
7+
## Key Features
8+
9+
### 1. Automatic Conflict Detection
10+
11+
When a document is opened or after reconciliation imports patches, the system:
12+
- Analyzes all patches with snapshot content
13+
- Identifies overlapping edits based on character ranges
14+
- Groups conflicting patches together
15+
- Displays an alert summarizing detected conflicts
16+
17+
### 2. Visual Timeline Indicators
18+
19+
Patches involved in conflicts are highlighted in the timeline with:
20+
- **Red border** on the timeline item
21+
- **Red background tint** for visibility
22+
- **Warning text** showing which other patches conflict (e.g., "⚠️ Conflicts with #3, #5")
23+
24+
### 3. Tabbed Diff Preview
25+
26+
When previewing a patch that's part of a conflict group:
27+
- **Conflict tabs** appear in the preview banner
28+
- Each tab represents a patch in the conflict group
29+
- Clicking a tab switches the diff view to that patch
30+
- The active patch is highlighted in red
31+
- Users can compare all conflicting patches side-by-side
32+
33+
### 4. Alert Notifications
34+
35+
When conflicts are detected:
36+
- An alert appears showing the number of conflict groups
37+
- Details about each group are listed (e.g., "Patches #3, #5 modify the same text")
38+
- Alerts are rate-limited to avoid spam during filtering/sorting
39+
40+
## Implementation Details
41+
42+
### Files Modified/Created
43+
44+
| File | Purpose |
45+
|------|---------|
46+
| `src/conflict-detection.js` | **NEW** - Core conflict detection logic |
47+
| `src/timeline.js` | Updated to integrate conflict detection and display indicators |
48+
| `src/diff-preview.js` | Updated to show conflict tabs and enable tab switching |
49+
| `src/reconcile.js` | Updated to trigger conflict detection after import |
50+
| `src/styles.css` | Added styles for conflict indicators and tabs |
51+
52+
### Conflict Detection Algorithm
53+
54+
The algorithm works as follows:
55+
56+
1. **Extract Edit Ranges**: For each patch, calculate character ranges affected by changes
57+
- Compare current snapshot with previous patch snapshot
58+
- Use character-level diff to identify insertions, deletions, and modifications
59+
- Merge adjacent/overlapping ranges
60+
61+
2. **Find Overlaps**: Compare edit ranges between patches from different authors
62+
- Skip comparisons between patches from the same author
63+
- Check if character ranges overlap
64+
- Record conflict relationships
65+
66+
3. **Group Conflicts**: Use breadth-first search to group related conflicts
67+
- If A conflicts with B, and B conflicts with C, they form one group [A, B, C]
68+
- Separate groups are maintained for independent conflicts
69+
70+
### Key Functions
71+
72+
#### `conflict-detection.js`
73+
74+
```javascript
75+
// Main detection function
76+
detectPatchConflicts(patches)
77+
// Returns: { conflictGroups, patchConflicts }
78+
79+
// Check if a patch is in conflict
80+
isInConflict(patchId, patchConflicts)
81+
// Returns: boolean
82+
83+
// Get conflict group for a patch
84+
getConflictGroup(patchId, conflictGroups)
85+
// Returns: Array of patch IDs or null
86+
87+
// Format conflict info for display
88+
formatConflictInfo(patchId, conflictingPatchIds)
89+
// Returns: string like "⚠️ Conflicts with #3, #5"
90+
```
91+
92+
#### `timeline.js`
93+
94+
```javascript
95+
// Get current conflict state
96+
getConflictState()
97+
// Returns: { conflictGroups, patchConflicts }
98+
```
99+
100+
## User Experience Flow
101+
102+
1. **Document Open or Reconciliation**
103+
- System automatically detects conflicts
104+
- Alert appears if conflicts found
105+
106+
2. **Timeline View**
107+
- Conflicting patches show red borders
108+
- Warning text indicates which patches conflict
109+
- Users can see at a glance which edits need attention
110+
111+
3. **Preview Mode**
112+
- Click "Preview" on any conflicting patch
113+
- Tabs appear for all patches in that conflict group
114+
- Switch between tabs to compare changes
115+
- Accept or reject individual patches
116+
117+
4. **Resolution**
118+
- Accept one patch (merges it into the document)
119+
- Reject others or keep for later review
120+
- Conflicts resolved by accepting/rejecting decisions
121+
122+
## Styling
123+
124+
### Timeline Conflict Indicators
125+
126+
```css
127+
.timeline-item.has-conflict {
128+
border-left: 3px solid #f44336;
129+
border-color: #f44336;
130+
background: rgba(244, 67, 54, 0.1);
131+
}
132+
133+
.conflict-warning {
134+
color: #f44336;
135+
font-size: 0.75rem;
136+
font-weight: 500;
137+
}
138+
```
139+
140+
### Conflict Tabs
141+
142+
```css
143+
.conflict-tab {
144+
border: 1px solid #f44336;
145+
background: var(--bg-panel);
146+
}
147+
148+
.conflict-tab.active {
149+
background: #f44336;
150+
color: white;
151+
font-weight: bold;
152+
}
153+
```
154+
155+
## Testing
156+
157+
### Manual Testing Scenarios
158+
159+
1. **No Conflicts**
160+
- Open document with patches from one author
161+
- Verify no red indicators appear
162+
- Verify no alert is shown
163+
164+
2. **Simple Conflict**
165+
- Import patches where two authors edit the same paragraph
166+
- Verify red borders appear on both patches
167+
- Verify alert shows conflict group
168+
- Click preview - verify tabs appear
169+
- Switch tabs - verify diff updates
170+
171+
3. **Multiple Conflict Groups**
172+
- Import patches with:
173+
- Patches A & B editing line 1 (Group 1)
174+
- Patches C & D editing line 10 (Group 2)
175+
- Verify each group is separate
176+
- Preview A - should only show A & B tabs
177+
- Preview C - should only show C & D tabs
178+
179+
4. **Three-Way Conflict**
180+
- Import patches where 3+ authors edit same text
181+
- Verify all appear in same conflict group
182+
- Preview any - verify all tabs appear
183+
184+
### Automated Testing
185+
186+
A test HTML file is provided at `test-conflict-detection.html` which can be opened in a browser to verify:
187+
- Non-overlapping patches detection
188+
- Overlapping edits detection
189+
- Same-author filtering
190+
- Multiple conflict groups
191+
- Edge cases (empty, single patch)
192+
193+
## Performance Considerations
194+
195+
- Conflict detection runs on every timeline refresh
196+
- Algorithm is O(n²) where n = number of patches
197+
- For typical documents (< 100 patches), this is negligible
198+
- Alert is rate-limited to once per 5 seconds
199+
- Conflict state is cached and only recalculated on data changes
200+
201+
## Future Enhancements
202+
203+
Potential improvements:
204+
1. Persist conflict resolutions across sessions
205+
2. Add "Accept All" / "Reject All" for conflict groups
206+
3. Show diff between conflicting versions side-by-side
207+
4. Highlight exact overlapping text regions in preview
208+
5. Suggest automatic merge strategies
209+
6. Add conflict statistics/dashboard
210+
211+
## Dependencies
212+
213+
- `diff-highlighter.js` - Character-level diff calculation
214+
- `timeline.js` - Patch list and filtering
215+
- `diff-preview.js` - Preview mode and banner
216+
- `three-way-merge.js` - Merge logic for accepting patches
217+
218+
## Browser Compatibility
219+
220+
Requires modern browsers with ES6+ support:
221+
- Chrome/Edge 88+
222+
- Firefox 78+
223+
- Safari 14+
224+
225+
## Credits
226+
227+
Implemented as part of the Korppi collaborative editing system.
228+
Based on the existing ConflictDetector in Rust (`src-tauri/src/conflict_detector.rs`).

0 commit comments

Comments
 (0)