Skip to content

Comments

Fix Mermaid code blocks broken on dashboard feed (#36582)#36604

Draft
silverwind wants to merge 3 commits intogo-gitea:mainfrom
silverwind:feedcut
Draft

Fix Mermaid code blocks broken on dashboard feed (#36582)#36604
silverwind wants to merge 3 commits intogo-gitea:mainfrom
silverwind:feedcut

Conversation

@silverwind
Copy link
Member

@silverwind silverwind commented Feb 12, 2026

Fixes: #36582

Fixes two bugs causing broken rendering of fenced code blocks in dashboard feed comments:

  1. Truncation at 200 chars could cut mid-code-block, leaving an unclosed fence that produces a parse error.

  2. The action content format index|body was parsed with SplitN(..., 3), but mermaid source can contain |, workaround by splitting only on the first |.

Before:

Screenshot 2026-02-12 at 20 41 13 Screenshot 2026-02-12 at 20 41 37

After:

Screenshot 2026-02-12 at 20 41 22 Screenshot 2026-02-12 at 20 41 44

Fix two bugs causing broken rendering of fenced code blocks (e.g. Mermaid
diagrams) in dashboard feed comments:

1. Truncation at 200 chars could cut mid-code-block, leaving an unclosed
   fence that produces a parse error. Add trimUnclosedCodeBlock() to strip
   the partial block after truncation.

2. The action content format "index|body" was parsed with SplitN(..., 3),
   splitting the comment body at its first "|" character. Mermaid syntax
   commonly uses "|" (e.g. "A -->|text| B"). Add GetIssueContentBody()
   which splits only on the first "|" and use it in the feed template.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@GiteaBot GiteaBot added the lgtm/need 2 This PR needs two approvals by maintainers to be considered for merging. label Feb 12, 2026
@github-actions github-actions bot added modifies/go Pull requests that update Go code modifies/templates This PR modifies the template files labels Feb 12, 2026
@silverwind silverwind requested a review from Copilot February 12, 2026 20:17
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Fixes broken Mermaid/Markdown rendering in the signed-in user dashboard activity feed by ensuring truncated comment previews don’t leave invalid/unclosed fenced blocks, and by correctly extracting comment bodies from Action.Content even when the body contains | (e.g. Mermaid edge labels).

Changes:

  • Update dashboard feed template to use a new Action.GetIssueContentBody() accessor instead of GetIssueInfos()[1] so | inside comment bodies is preserved.
  • Add trimUnclosedCodeBlock to strip trailing unclosed fenced code blocks from truncated comment previews before rendering.
  • Add unit tests for trimUnclosedCodeBlock.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
templates/user/dashboard/feeds.tmpl Switches dashboard feed comment rendering to a body accessor that doesn’t break on `
services/feed/notifier.go Trims truncated comment previews to avoid unclosed fenced code blocks breaking Markdown/Mermaid rendering.
services/feed/notifier_test.go Adds unit tests covering unclosed/closed fenced code block trimming behavior.
models/activities/action.go Adds GetIssueContentBody() to split action content on the first `

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

…dy test

Only call trimUnclosedCodeBlock when truncation actually occurred, and
add unit tests for GetIssueContentBody covering pipe-delimited content.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Contributor

@wxiaoguang wxiaoguang left a comment

Choose a reason for hiding this comment

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

I don't think it is right.

I think mermaid shouldn't be rendered in the timeline event. In my mind, timeline is only used for showing the summary of the changed contents, but not a full diagram.

Actually the problem is also same to:

  • truncated math blocks (inline) ` `
  • truncated attachments
  • truncated HTML tags and links

And more. The timeline shouldn't render these uncontrollable code blocks

Instead of silently removing the content, a placeholder should be there, otherwise it would read very strange to end users.

Maybe either:

  1. Don't render the content as markdown, only show the raw content as-is (strip HTML tags)
  2. Only do simple rendering based on 1 (just like commit messages, only simple back-quotes and links)
  3. Still render the content as markdown, and do more processing for the rendered content, replace uncontrollable blocks with placeholders

@GiteaBot GiteaBot added lgtm/blocked A maintainer has reservations with the PR and thus it cannot be merged and removed lgtm/need 2 This PR needs two approvals by maintainers to be considered for merging. labels Feb 13, 2026
@silverwind
Copy link
Member Author

silverwind commented Feb 13, 2026

I think mermaid shouldn't be rendered in the timeline event. In my mind, timeline is only used for showing the summary of the changed contents, but not a full diagram.

I guess it makes sense, but we currently also currently render images in the timeline which can expand to huge rendered blocks. If we omit mermaid, we ought to emit any other non-text content as well and only render text. I think that makes sense and should be easier to implement too.

@tyroneyeh
Copy link
Contributor

tyroneyeh commented Feb 13, 2026

Hi @silverwind

I'd like to improve the trimUnclosedCodeBlock functionality as follows. Can I push this directly to your branch?

Thanks,

Details
diff --git a/services/feed/notifier.go b/services/feed/notifier.go
index 0acc0c59e1..3ac2587af6 100644
--- a/services/feed/notifier.go
+++ b/services/feed/notifier.go
@@ -31,31 +31,41 @@ type actionNotifier struct {
 // the renderer tries (and fails) to process. This function detects the
 // situation and strips the partial block.
 func trimUnclosedCodeBlock(s string) string {
+       lines := strings.Split(s, "\n")
        inBlock := false
-       lastOpenIdx := -1
-       i := 0
-       for i < len(s) {
-               lineStart := i
-               lineEnd := strings.Index(s[i:], "\n")
-               var line string
-               if lineEnd == -1 {
-                       line = s[i:]
-                       i = len(s)
-               } else {
-                       line = s[i : i+lineEnd]
-                       i = i + lineEnd + 1
+       fenceChar := byte(0)
+       fenceLen := 0
+
+       for _, line := range lines {
+               trimmed := strings.TrimLeft(line, " ")
+               if len(trimmed) < 3 {
+                       continue
                }
-               if strings.HasPrefix(strings.TrimLeft(line, " "), "```") {
+
+               if strings.HasPrefix(trimmed, "```") || strings.HasPrefix(trimmed, "~~~") {
+                       char := trimmed[0]
+                       count := 1
+                       for count < len(trimmed) && trimmed[count] == char {
+                               count++
+                       }
+
                        if !inBlock {
-                               lastOpenIdx = lineStart
                                inBlock = true
-                       } else {
+                               fenceChar = char
+                               fenceLen = count
+                       } else if char == fenceChar && count >= fenceLen {
                                inBlock = false
                        }
                }
        }
-       if inBlock && lastOpenIdx >= 0 {
-               return strings.TrimRight(s[:lastOpenIdx], " \t\n")
+
+       if inBlock && fenceLen > 0 {
+               s = strings.TrimRight(s, " \t\n")
+               if strings.HasSuffix(s, "…") {
+                       s = strings.TrimRight(s, "…") + "\n" + strings.Repeat(string(fenceChar), fenceLen) + "\n…"
+               } else {
+                       s += "\n" + strings.Repeat(string(fenceChar), fenceLen) + "\n"
+               }
        }
        return s
 }

@wxiaoguang
Copy link
Contributor

wxiaoguang commented Feb 13, 2026

I'd like to improve the trimUnclosedCodeBlock functionality as follows. Can I push this directly to your branch?

I think you should read and understand this first. #36604 (review)

By the way, your "trim" is not right. You are just trying to write a new incorrect parser&render.

Sample:

Details
```
```
````
```
```
````
image

@tyroneyeh
Copy link
Contributor

tyroneyeh commented Feb 13, 2026

I updated the patch, is that okay?

Details image image

@silverwind
Copy link
Member Author

silverwind commented Feb 13, 2026

My current plan is eliminate code blocks if their line count exceeds like 5-10 lines or if the total character count is above 200 and it would cut off the block. Mermaid blocks will always be eliminated, Math blocks likely also. Images as well. Goal is to keep the frontpage feed compact.

@tyroneyeh I think it's better that you not try. I will exercise Claude on it which should produce something useable given these clear success criteria.

@wxiaoguang
Copy link
Contributor

wxiaoguang commented Feb 13, 2026

I updated the patch, is that okay?

Certainly you haven't read or understood #36604 (review)

Why such a large diagram in timeline makes sense?

"You are just trying to write a new incorrect parser&render."

What if the truncation occurs in the diagram syntax?

@tyroneyeh
Copy link
Contributor

The timeline is mainly intended to show a summary of changes, not the full content.
If truncation occurs within code blocks or Mermaid diagrams, rendering them fully may fail.
Therefore, my approach is to replace truncated code or Mermaid blocks with placeholders (e.g., [code omitted], [Mermaid diagram omitted]), while preserving the trailing ….
This way, users know that content has been truncated, timeline rendering remains safe, and the interface stays clean.

@silverwind
Copy link
Member Author

silverwind commented Feb 13, 2026

Hmm @wxiaoguang had suggested placeholders as well, but I'm not sold on the idea. The whole point of the feed is to give a very concise preview, I see no point in littering the feed with placeholders.

@wxiaoguang
Copy link
Contributor

I mean "either" with these suggestions. Placeholders can be used for some special cases for example a <video> tag is not suitable to be rendered directly, just in case, just an idea.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

lgtm/blocked A maintainer has reservations with the PR and thus it cannot be merged modifies/go Pull requests that update Go code modifies/templates This PR modifies the template files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Mermaid code block truncated on homepage causes parse error

4 participants