Skip to content

Conversation

LexioJ
Copy link

@LexioJ LexioJ commented Sep 6, 2025

🎯 Overview

This PR introduces a comprehensive visual diff system that transforms how card description changes are displayed in the activity feed, making it easier for users to understand what exactly changed in their content.

Resolves #7201

✨ Features

🔍 Smart Change Detection

  • Intelligent Move Detection (🚚): Identifies when lines are relocated without modification
  • Word-Level Modifications (✏️): Highlights specific word changes within lines using combined <del>/<ins> HTML tags for cleaner output
  • Clean Additions/Deletions (✨/🗑️): Clear indicators for new or removed content
  • Checkbox State Tracking: Special handling for task list changes with visual emoji transitions
  • Quote Line Handling: Properly formats blockquotes with ❞ emoji (fixes &gt; display issues)
  • Callout Block Transitions: Shows emoji transitions for callout type changes (ℹ️→❗, ✅→⚠️, etc.)
  • Code Block Indicators: Displays code block markers with ‹› symbol

🎭 Professional Visual Indicators

  • 🚚 Move operations: "🚚5 Line content (from 2)"
  • ✏️ Modifications with combined tags: "✏️3 Old contentNew content"
  • Additions: "✨2 New content"
  • 🗑️ Deletions: "🗑️4 Removed content"
  • Special Line Types:
    • Checkboxes: "☑️→🔲" or "🔲→☑️"
    • Callouts: "ℹ️→❗" (info to error)
    • Quotes: "→❞ Quoted text"
    • Code blocks: "→‹›"

🧠 Intelligent Filtering & Optimization

  • Filters out unchanged content to reduce noise
  • Ignores empty line operations that don't add value
  • Combines consecutive <ins> and <del> tags to reduce visual clutter
  • Merges whitespace between tags for cleaner output (e.g., <del>text 1 text 2</del> instead of <del>text 1</del> <del>text 2</del>)
  • Provides line number context for better orientation
  • Activity feed compatible: Uses plain text formatting that displays correctly without HTML escaping issues

🛠 Technical Implementation

Core Components

  1. DiffService: Service implementing LCS-based diff algorithm with multi-pass detection
  2. Enhanced DeckProvider: Updated activity provider with dependency injection for DiffService
  3. Smart Algorithm Flow:
    • Pass 1: Content analysis and operation extraction
    • Pass 2: Move detection (exact matches at different positions)
    • Pass 3: Modification detection with special line handling:
      • Checkbox state changes
      • Callout block type changes
      • Quote line changes (prevents &gt; issues)
    • Pass 4: Word-level diff with combined HTML tags
    • Pass 5: Remaining operations (pure adds/deletes)

Algorithm Highlights

  • Longest Common Subsequence (LCS) for optimal diff detection
  • Similarity scoring system for intelligent operation pairing
  • Multi-pass processing ensures accurate classification
  • Tag combination logic merges consecutive <ins>/<del> tags and whitespace-only keep operations
  • HTML-safe output compatible with Nextcloud's activity feed constraints

Activity Feed Compatibility Fixes

  • Removed reliance on HTML rendering in activity feed
  • Special handling for > character to prevent &gt; display issues
  • Quote lines detected and formatted with emoji before HTML escaping
  • All special patterns handled with plain text + emoji approach

📸 Visual Examples

Word-Level Changes

Before: John Doe changed the description
After: ✏️2 Update <del>deadline</del><ins>timeline</ins>

Checkbox Changes

Before: John Doe changed the description
After: ✏️1 🔲→☑️ Task completed

Callout Block Changes

Before: John Doe changed the description
After: ✏️5 ℹ️→❗

Quote Changes

Before: John Doe changed the description (displayed as &gt; text)
After: ✏️3 →❞ Important note

Combined Tags (Cleaner Output)

Before: ✏️5 <del>```</del><ins>-</ins><ins> </ins><ins>[x]</ins><ins> </ins><ins>ToDo</ins><ins> </ins><ins>1</ins>
After: ✏️5 <del>```</del><ins>- [x] ToDo 1</ins>

🧪 Testing

Extensively tested with various scenarios:

  • ✅ Simple line moves and modifications
  • ✅ Complex multi-operation changes
  • ✅ Checkbox state transitions
  • ✅ Callout block type changes (info, success, warn, error)
  • ✅ Quote line handling and &gt; fix
  • ✅ Code block markers
  • ✅ Empty content and edge cases
  • ✅ Large content blocks and performance
  • ✅ HTML tag combination and whitespace merging
  • ✅ Activity feed compatibility (no more escaped HTML)

🚀 Benefits

For Users

  • Clear Understanding: See exactly what changed in card descriptions
  • Reduced Cognitive Load: Filter out noise, focus on meaningful changes
  • Better Context: Line numbers and move tracking provide better orientation
  • Professional Presentation: Clean, modern emoji-based indicators
  • Proper Quote Display: No more &gt; characters in activity feed
  • Cleaner Diff Output: Combined HTML tags reduce visual clutter

For Developers

  • Maintainable Code: Clean service architecture with separation of concerns
  • Dependency Injection: Proper DI container registration for DiffService
  • Extensible Design: Easy to extend for other content types
  • Performance Optimized: Efficient algorithms with minimal overhead
  • Backward Compatible: Existing functionality remains unchanged
  • Activity Feed Safe: Handles all HTML escaping edge cases

🔧 Configuration

No configuration required - the feature works out of the box with existing Deck installations.

📋 Changelog

Latest Updates

  • Quote Line Handling: Fixed &gt; display issues in activity feed for quote lines
  • Combined HTML Tags: Reduced visual clutter by merging consecutive <ins>/<del> tags
  • Whitespace Merging: Improved tag combination to include whitespace between add/remove operations
  • Updated Emojis:
    • Error callout: 🔴 → ❗ (better matches UI)
    • Quote blocks: 💬 → ❞ (quotation mark)
    • Code blocks: 📝 → ‹› (guillemets)
  • Dependency Injection: Proper DI registration for DiffService

Code Review Feedback Addressed

  • Copyright year updated to 2025
  • Checkbox pattern extracted as class constant
  • Unused parameters removed
  • DiffService properly registered in DI container
  • Consistent line numbering (shows actual line numbers from content)
  • Activity feed compatibility verified and fixed

🤝 Contributing

This implementation focuses on card description changes but the DiffService architecture is designed to be extensible for other content types in the future.


This PR represents a significant enhancement to user experience by providing clear, actionable insights into content changes while maintaining the professional quality expected from Nextcloud applications.

@LexioJ LexioJ force-pushed the feature/visual-diff-7201-v1.15.2 branch 2 times, most recently from f83b4b9 to 8b42605 Compare September 6, 2025 18:16
@putt1ck
Copy link

putt1ck commented Sep 7, 2025

Looks interesting. Does it also address #7058?

@LexioJ
Copy link
Author

LexioJ commented Sep 7, 2025

Looks interesting. Does it also address #7058?

Hard to tell as issue #7058 seems to discuss the overall appearance within the activity app and a wrong description notification when only comments were made.

This PR indeed addresses the need to reduce bloating the activity log, but only within the activity tab of the corresponding card. It focuses on the deck app itself.

@marcoambrosini marcoambrosini self-requested a review September 12, 2025 10:33
@LexioJ LexioJ force-pushed the feature/visual-diff-7201-v1.15.2 branch 7 times, most recently from b5f9e4b to 86df615 Compare September 19, 2025 14:09
@LexioJ LexioJ force-pushed the feature/visual-diff-7201-v1.15.2 branch from 86df615 to e8b1112 Compare September 20, 2025 05:24
Copy link
Contributor

Hello there,
Thank you so much for taking the time and effort to create a pull request to our Nextcloud project.

We hope that the review process is going smooth and is helpful for you. We want to ensure your pull request is reviewed to your satisfaction. If you have a moment, our community management team would very much appreciate your feedback on your experience with this PR review process.

Your feedback is valuable to us as we continuously strive to improve our community developer experience. Please take a moment to complete our short survey by clicking on the following link: https://cloud.nextcloud.com/apps/forms/s/i9Ago4EQRZ7TWxjfmeEpPkf6

Thank you for contributing to Nextcloud and we hope to hear from you soon!

(If you believe you should not receive this message, you can add yourself to the blocklist.)

@LexioJ LexioJ force-pushed the feature/visual-diff-7201-v1.15.2 branch 8 times, most recently from 2a58b7c to 40315b9 Compare September 28, 2025 05:36
@LexioJ LexioJ force-pushed the feature/visual-diff-7201-v1.15.2 branch from 40315b9 to 0f5ec86 Compare September 29, 2025 21:34
Copy link
Contributor

@luka-nextcloud luka-nextcloud left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your contribution. The line number seems incorrect.

image image

$this->l10nFactory = $l10n;
$this->config = $config;
$this->cardService = $cardService;
$this->diffService = new DiffService();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The DiffService can be inject via the constructor instead of instantiating it directly

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Year in copyright text should be 2025

*/
private function isCheckboxChange(string $oldLine, string $newLine): bool {
// Pattern for markdown checkboxes: - [ ] or - [x] or - [X]
$checkboxPattern = '/^(\s*-\s*)\[([ xX])\](.*)/i';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The checkbox pattern can be defined as a constant to avoid duplicate code

* @return string
*/
private function generateCheckboxDiff(string $oldLine, string $newLine): string {
$checkboxPattern = '/^(\s*-\s*)\[([ xX])\](.*)/i';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The checkbox pattern can be defined as a constant to avoid duplicate code

* @param array $newLines
* @return string
*/
private function enhanceWithWordLevelDiff(string $html, array $operations, array $oldLines, array $newLines): string {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The $html is not used anywhere

}

// Add remaining unused remove operations (not involved in moves or modifications)
foreach ($removes as $removeIndex => $removeOp) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The $removeIndex is not used

@LexioJ LexioJ force-pushed the feature/visual-diff-7201-v1.15.2 branch from 5cca5d9 to bdd5fe0 Compare October 4, 2025 22:25
@LexioJ LexioJ requested a review from luka-nextcloud October 4, 2025 22:26
@LexioJ LexioJ force-pushed the feature/visual-diff-7201-v1.15.2 branch 6 times, most recently from 6c5db9d to 60eb522 Compare October 11, 2025 17:30
@LexioJ LexioJ force-pushed the feature/visual-diff-7201-v1.15.2 branch 2 times, most recently from 314af8a to 57c59a5 Compare October 17, 2025 20:10
@LexioJ LexioJ force-pushed the feature/visual-diff-7201-v1.15.2 branch from 57c59a5 to c9f2fc0 Compare October 21, 2025 05:29
This commit introduces a sophisticated visual diff system that enhances
the activity feed with intelligent change detection and professional
presentation. Resolves issue nextcloud#7201.

Features:
• Smart diff rendering with emoji indicators (➕✏️🗑️🚚)
• Word-level diffing for modifications with <del>/<ins> HTML tags
• Intelligent move detection for relocated unchanged content
• Special handling for checkbox state transitions (☐ ↔ ☑)
• Line number context preservation for better readability
• Noise filtering (empty lines, unchanged content)

Technical Implementation:
• New DiffService with LCS-based diff algorithm
• Enhanced activity provider with diff integration
• Multi-pass detection: moves → modifications → additions/deletions
• Similarity scoring system for optimal operation pairing
• HTML-safe output compatible with activity feed constraints

Benefits:
• Clear visualization of content changes in activity timeline
• Reduced cognitive load with filtered, relevant changes only
• Professional emoji-based change indicators
• Maintains backward compatibility with existing activity system

The system intelligently distinguishes between:
- Line moves (🚚): Exact content relocated to different position
- Modifications (✏️): Content changes with word-level highlighting
- Additions (➕): New content inserted
- Deletions (🗑️): Content removed

Tested extensively with various scenarios including complex multi-operation
changes, edge cases, and performance considerations.

Signed-off-by: Alexander Askin <[email protected]>
- Apply PHP-CS-Fixer formatting to DiffService.php
  - Fix tab indentation and control structure braces
  - Align with Nextcloud coding standards
- Update test expectation for visual diff feature
  - Adjust DeckProviderTest to expect new diff output format
  - Test now expects '✏️1 <del>ABC</del>→<ins>BCD</ins>' instead of 'BCD'

Fixes failing php-cs and phpunit checks in CI

Signed-off-by: Alexander Askin <[email protected]>
- Fix line numbering to consistently show positions in NEW text
- Use dependency injection for DiffService in DeckProvider
- Update copyright year to 2025
- Extract checkbox pattern as class constant
- Remove unused $html parameter and $removeIndex variable
- Fix duplicate remove operations tracking
- Enhance checkbox change detection to handle text modifications
- Add special line formatting for code blocks, callouts, and quotes
- Improve visual presentation with emojis and separators
- Shorten move notation from "(moved from line X)" to "(from X)"

Signed-off-by: Alexander Askin <[email protected]>
- Remove HTML tags (<ins>, <del>) from diff output for activity feed compatibility
- Add callout block emoji transitions (e.g., ℹ️→🔴 for ::: info → ::: error)
- Use plain text with arrows (→) to show changes instead of HTML formatting

The activity feed doesn't support HTML tags properly, causing them to appear
as escaped text. This change uses plain text formatting that displays correctly.

Signed-off-by: Alexander Askin <[email protected]>
- Add quote line detection and formatting for MODIFY operations to prevent &gt; display issues
- Combine consecutive <ins> and <del> tags to reduce visual clutter
- Merge whitespace-only keep operations between add/remove tags for cleaner output
- Update emoji symbols for better visual representation:
  - Error callout: 🔴 → ❗ (exclamation mark)
  - Quote blocks: 💬 → ❞ (quotation mark)
  - Code blocks: 📝 → ‹› (guillemets)

Signed-off-by: Alexander Askin <[email protected]>
@LexioJ LexioJ force-pushed the feature/visual-diff-7201-v1.15.2 branch from c9f2fc0 to c1c3510 Compare October 21, 2025 20:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature request: Visual diff-style output for card description changes

3 participants