Stand with Ukraine 🇺🇦

Show Jira Issue Comments — Confluence Cloud Macro

external-content

This Confluence user macro calls the Jira REST API to fetch comments, then recursively parses comment body nodes using a Velocity #macro to extract plain text. The result is rendered in an AUI table with sorting enabled and supplemented by AUI elements such as avatars and lozenges for authors and timestamps.

Try for free

User Parameters

Issue ID or Key

Enter a Jira issue ID or key

Order

Choose the order in which comments are displayed (ASC or DESC by creation date)

123

maxResults

Set the maximum number of items to return

Template

## Parameters:
## issueIdOrKey (required) - Jira issue ID or key to fetch comments for
## order (optional) - ASC / DESC (defaults to created ascending)
## maxResults (optional) - number of comments to request (Jira default is 100)

#set($issueIdOrKey = $parameters["issueIdOrKey"])

#if(!$issueIdOrKey)
## Display a message if issueIdOrKey is not provided
<div role="note" aria-labelledby="no-issue-key-title" class="aui-message aui-message-info" style="width:100%; height: 100%;">
    <p id="no-issue-key-title" class="title">
        Note: Issue key/id not provided
    </p>
    <p>
        Please set the <code>issueIdOrKey</code> parameter for this macro.
    </p>
</div>

#else

#set($rawOrder = $parameters["order"])
#set($orderBy = "created")
#if($rawOrder)
#set($order = $rawOrder.toUpperCase())
#if($order == "ASC")
#set($orderBy = "+created")
#elseif($order == "DESC")
#set($orderBy = "-created")
#end
#end

#set($maxResultsParam = "")
#set($maxResultsInput = $parameters["maxResults"])
#if($maxResultsInput)
#set($maxResultsParam = "&maxResults=" + $maxResultsInput)
#end

## Fetch comments
#set($requestUrl = "/rest/api/3/issue/" + $issueIdOrKey + "/comment?orderBy=" + $orderBy + $maxResultsParam)
#set($response = $JiraManager.get($requestUrl).comments)

#set($parsePattern = "yyyy-MM-dd'T'HH:mm:ss.SSSZ")

## Build a table if there are comments
#if($response && $response.size() > 0)
<table class="aui aui-table-sortable" style="width:100%;">
    <thead>
        <tr>
            <th>Author</th>
            <th>Comment</th>
            <th class="aui-table-column-unsortable">Created 🟢 / Updated 🟣</th>
        </tr>
    </thead>
    <tbody>
        #foreach($c in $response)
        #set($auth = $c.updateAuthor)
        #if(!$auth)
        #set($auth = $c.author)
        #end

        #set($displayName = $auth.displayName)
        #set($avatar = $auth.avatarUrls.get("48x48"))
        #if(!$avatar)
        #set($avatar = "https://icon-library.com/images/avatar-icon-images/avatar-icon-images-4.jpg")
        #end

        ## Format dates
        #set($createdFormatted = "")
        #if($c.created)
        #set($createdFormatted = $DateUtils.parseDate($c.created, $parsePattern))
        #end

        #set($updatedFormatted = "")
        #if($c.updated)
        #set($updatedFormatted = $DateUtils.parseDate($c.updated, $parsePattern))
        #end

        ## Render ADF to HTML
        #set($html = "")
        #set($stack = $c.body.content)

        #foreach($lvl in [1..20])
        #set($next = [])

        #foreach($node in $stack)

        ## Paragraph
        #if($node.type == "paragraph")
        #set($p = "")
        #if($node.content)
        #foreach($n in $node.content)
        #if($n.text)
        #set($p = $p + $n.text)
        #end
        #end
        #end
        #set($html = $html + "<p>" + $p + "</p>")
        #end

        ## Bullet List
        #if($node.type == "bulletList")
        #set($html = $html + "<ul>")
        #foreach($item in $node.content)
        #set($li = "")
        #foreach($pnode in $item.content)
        #foreach($t in $pnode.content)
        #if($t.text)
        #set($li = $li + $t.text)
        #end
        #end
        #end
        #set($html = $html + "<li>" + $li + "</li>")
        #end
        #set($html = $html + "</ul>")
        #end

        ## Ordered List
        #if($node.type == "orderedList")
        #set($html = $html + "<ol>")
        #foreach($item in $node.content)
        #set($li = "")
        #foreach($pnode in $item.content)
        #foreach($t in $pnode.content)
        #if($t.text)
        #set($li = $li + $t.text)
        #end
        #end
        #end
        #set($html = $html + "<li>" + $li + "</li>")
        #end
        #set($html = $html + "</ol>")
        #end

        ## Fallback recursion
        #if($node.content)
        #foreach($c2 in $node.content)
        #set($discard = $next.add($c2))
        #end
        #end

        #end

        #if(!$next || $next.size() == 0)
        #break
        #end

        #set($stack = $next)
        #end

        #if($html == "")
        #set($html = "(no text)")
        #end


        <tr>
            <td style="vertical-align:middle;">
                <div style="display:flex; align-items:center;">
                    <div>
                        <aui-avatar size="medium" type="user" src="$avatar" title="$displayName" alt="avatar-$displayName"></aui-avatar>
                    </div>
                    <div style="margin-left:10px; line-height:1.1;">
                        $!displayName
                    </div>
                </div>
            </td>

            <td style="word-break:break-word; vertical-align: middle;">
                $html
            </td>

            <td style="white-space:nowrap;">
                #if($createdFormatted)
                <span class="aui-lozenge aui-lozenge-subtle aui-lozenge-success">$createdFormatted</span><br>
                #end
                #if($updatedFormatted)
                <span class="aui-lozenge aui-lozenge-subtle aui-lozenge-new">$updatedFormatted</span>
                #end
            </td>
        </tr>
        #end
    </tbody>
</table>

#else
## Display a message if no comments found
<div role="note" aria-labelledby="no-comments-title" class="aui-message aui-message-info" style="width:100%; height:100%;">
    <p id="no-comments-title" class="title">
        No comments found
    </p>
    <p>
        Please check the <code>issueIdOrKey</code> or try another issue.
    </p>
</div>
#end

#end