Fix Mermaid code blocks broken on dashboard feed (#36582)#36604
Fix Mermaid code blocks broken on dashboard feed (#36582)#36604silverwind wants to merge 3 commits intogo-gitea:mainfrom
Conversation
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>
There was a problem hiding this comment.
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 ofGetIssueInfos()[1]so|inside comment bodies is preserved. - Add
trimUnclosedCodeBlockto 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>
There was a problem hiding this comment.
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:
- Don't render the content as markdown, only show the raw content as-is (strip HTML tags)
- Only do simple rendering based on 1 (just like commit messages, only simple back-quotes and links)
- Still render the content as markdown, and do more processing for the rendered content, replace uncontrollable blocks with placeholders
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. |
|
Hi @silverwind I'd like to improve the trimUnclosedCodeBlock functionality as follows. Can I push this directly to your branch? Thanks, Detailsdiff --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
} |
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: |
|
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. |
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? |
|
The timeline is mainly intended to show a summary of changes, not the full content. |
|
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. |
|
I mean "either" with these suggestions. Placeholders can be used for some special cases for example a |



Fixes: #36582
Fixes two bugs causing broken rendering of fenced code blocks in dashboard feed comments:
Truncation at 200 chars could cut mid-code-block, leaving an unclosed fence that produces a parse error.
The action content format
index|bodywas parsed withSplitN(..., 3), but mermaid source can contain|, workaround by splitting only on the first|.Before:
After: