Files
haproxy-openmanager/frontend/src
taylanbakircioglu 01ae508d39 feat: Line-by-line diff for multi-line fields + rollback merge strategy
USER FEEDBACK SUMMARY:
1. "Old/New görünümü karışık, sadece yeni eklenen görünsün"
2. "Merge logic silme işlemini engelliyor, geri al"

CHANGES OVERVIEW:
 Backend: Rolled back merge strategy (prevents deletion issue)
 Frontend: Added line-by-line diff renderer (cleaner UX)

═══════════════════════════════════════════════════════════

PART 1: BACKEND ROLLBACK (config.py)
═══════════════════════════════════════════════════════════

REMOVED: merge_multiline_field() function
REASON: Merge strategy was additive-only, prevented deletion

OLD BEHAVIOR (MERGE):
DB:     "option http-keep-alive"
Config: "option forwardfor"
Result: "option http-keep-alive\noption forwardfor"  ← BOTH kept!
Issue:  User CANNOT delete http-keep-alive 

NEW BEHAVIOR (REPLACE):
DB:     "option http-keep-alive"
Config: "option forwardfor"
Result: "option forwardfor"  ← Old deleted! ✓
Works:  Deletion and addition both work ✓

ROLLBACK DETAILS:
- Removed merge_multiline_field() function (lines 30-71)
- Restored simple comparison for frontend fields:
  * request_headers: simple != comparison
  * response_headers: simple != comparison
  * options: simple != comparison
  * tcp_request_rules: simple != comparison

- Restored simple comparison for backend fields:
  * request_headers: simple != comparison
  * response_headers: simple != comparison
  * options: simple != comparison

USER CONFIRMATION:
"aslında bu senaryoyu denedim. entitiy'de option http-keep-alive
varken option forwardfor'ı da ekledim. Confirm & Create Entitiy
dedikten sonra oluşan versiyon sadece yeni eklenen option forwardfor'u
dahil edecek şekilde oluştu. Yani sağlıklı çalıştı ve önceki option'u
kaldırmadı."

ANALYSIS: User's config ALREADY HAD both options!
Parser extracted: "option http-keep-alive\noption forwardfor"
No data loss occurred because BOTH were in the imported config.

═══════════════════════════════════════════════════════════

PART 2: FRONTEND LINE-BY-LINE DIFF (BulkConfigImport.js)
═══════════════════════════════════════════════════════════

NEW FEATURE: Smart line-by-line diff rendering

PROBLEM (User's Example):
DB:     "option http-keep-alive"
Config: "option http-keep-alive\noption forwardfor"

Old Preview (Confusing):
  Old: option http-keep-alive
  New: option http-keep-alive
       option forwardfor
  → User can't see what changed! 

New Preview (Clear):
  Added:
  + option forwardfor
  → Only changes shown! ✓

IMPLEMENTATION:

1. calculateLineDiff() Helper Function:
   - Splits old/new into lines
   - Trims whitespace and filters empty lines
   - Uses Set comparison for efficient diff
   - Returns: { added: [], removed: [], unchanged: [] }

   Algorithm:
   oldSet = Set(oldLines)
   newSet = Set(newLines)
   added = newLines.filter(line => !oldSet.has(line))
   removed = oldLines.filter(line => !newSet.has(line))

2. MultiLineDiffRenderer Component:
   - No changes: Shows plain text
   - Has changes: Shows diff boxes
   - Removed lines: Red box with - prefix
   - Added lines: Green box with + prefix
   - Unchanged lines: HIDDEN (per user request!)

APPLIED TO 7 FIELDS:

Frontend Entity (4 fields):
✓ frontend.options               (line 1097)
✓ frontend.request_headers        (line 1116)
✓ frontend.response_headers       (line 1135)
✓ frontend.tcp_request_rules      (line 1154)

Backend Entity (3 fields):
✓ backend.options                 (line 1228)
✓ backend.request_headers         (line 1248)
✓ backend.response_headers        (line 1268)

EDGE CASES HANDLED:
✓ Both null: No crash, returns empty arrays
✓ Old null: Shows all as added (green)
✓ New null: Shows all as removed (red)
✓ Empty lines: Filtered out before comparison
✓ Whitespace: Trimmed before comparison
✓ Duplicates: Set ensures unique comparison

VISUAL DESIGN:
- Removed box: #fff1f0 bg, #ff4d4f border, red text
- Added box: #f6ffed bg, #52c41a border, green text
- Spacing: 8px margin between boxes
- Font: 11px code font for readability
- Labels: 10px secondary text ("Removed:", "Added:")

USER FEEDBACK:
"neden old gösteriyor ki aslında sadece New: option forwardfor
gösterse daha doğru olmaz mı?"

RESPONSE: Absolutely! Removed unchanged section completely.

═══════════════════════════════════════════════════════════

TEST SCENARIOS:
═══════════════════════════════════════════════════════════

Scenario 1: Addition Only
Old: "option http-keep-alive"
New: "option http-keep-alive\noption forwardfor"
Result: Shows "+ option forwardfor" (green) ✓

Scenario 2: Deletion Only
Old: "option http-keep-alive\noption forwardfor"
New: "option http-keep-alive"
Result: Shows "- option forwardfor" (red) ✓

Scenario 3: Replacement
Old: "option http-keep-alive"
New: "option forwardfor"
Result: Shows "- option http-keep-alive" (red)
        and "+ option forwardfor" (green) ✓

Scenario 4: No Change
Old: "option http-keep-alive"
New: "option http-keep-alive"
Result: Plain text, no diff boxes ✓

Scenario 5: Empty Lines & Whitespace
Old: "  option http-keep-alive  \n\noption forwardfor"
New: "option http-keep-alive\noption forwardfor"
Result: No diff (trimmed and filtered) ✓

═══════════════════════════════════════════════════════════

SYSTEMATIC VERIFICATION COMPLETED:
═══════════════════════════════════════════════════════════

Backend Analysis:
✓ merge_multiline_field removed
✓ No merge logic in frontend comparison
✓ No merge logic in backend comparison
✓ Simple != comparison restored
✓ Deletion works correctly

Frontend Analysis:
✓ calculateLineDiff helper correct
✓ MultiLineDiffRenderer renders correctly
✓ Unchanged section removed
✓ 7 fields updated (3 backend + 4 frontend)
✓ Props passed correctly
✓ Edge cases handled
✓ No debug code left
✓ Badge colors consistent

No Side Effects:
✓ Backend edit modal: Still works
✓ Version diff: No impact
✓ Apply management: No impact
✓ Bulk create endpoint: No changes
✓ Other fields: Unaffected

BACKWARD COMPATIBILITY: ✓
PERFORMANCE: No performance impact (Set operations O(n))
CODE QUALITY: Clean, DRY, maintainable
2025-11-13 10:12:30 +03:00
..
2025-10-27 12:14:03 +03:00
2025-10-27 12:14:03 +03:00
2025-10-27 12:14:03 +03:00
2025-10-27 12:14:03 +03:00
2025-10-27 12:14:03 +03:00