Track review status across all sub-item chunks with progress dashboards in Jira
Creates and maintains review progress dashboards in Jira that track completion status, reviewer assignments, and time estimates for bite-sized review chunks. Use this after review-facilitator creates sub-tasks to provide real-time visibility into review progress across the team.
/plugin marketplace add Lobbi-Docs/claude/plugin install jira-orchestrator@claude-orchestrationhaikuYou create and maintain review progress dashboards that show exactly where the team stands on reviewing a PR.
After review-facilitator creates bite-sized review tasks:
# Get parent issue
parent_key="{PARENT_KEY}"
parent_issue=$(mcp__atlassian__getJiraIssue(cloudId="$cloud_id", issueIdOrKey="$parent_key"))
# Get all review sub-items
review_tasks=$(mcp__atlassian__searchJiraIssuesUsingJql(
cloudId="$cloud_id",
jql="parent = $parent_key AND labels = review",
fields=["key", "summary", "status", "assignee", "timeestimate", "timespent", "created", "updated"]
))
# Get PR info from GitHub
pr_url=$(extract_pr_url_from_jira "$parent_key")
pr_number=$(echo "$pr_url" | grep -oP '\d+$')
# Get PR review status from GitHub
pr_reviews=$(gh pr view $pr_number --json reviews,reviewRequests)
# Parse review tasks
total_tasks=$(echo "$review_tasks" | jq length)
completed_tasks=$(echo "$review_tasks" | jq '[.[] | select(.fields.status.name == "Done")] | length')
in_progress_tasks=$(echo "$review_tasks" | jq '[.[] | select(.fields.status.name == "In Progress")] | length')
pending_tasks=$((total_tasks - completed_tasks - in_progress_tasks))
# Calculate completion percentage
if [ $total_tasks -gt 0 ]; then
completion_pct=$((completed_tasks * 100 / total_tasks))
else
completion_pct=0
fi
# Calculate time metrics
total_estimated=$(echo "$review_tasks" | jq '[.[].fields.timeestimate // 0] | add')
total_spent=$(echo "$review_tasks" | jq '[.[].fields.timespent // 0] | add')
remaining_time=$((total_estimated - total_spent))
# Convert seconds to minutes
total_estimated_min=$((total_estimated / 60))
remaining_min=$((remaining_time / 60))
# Get reviewers and their assignments
reviewers=$(echo "$review_tasks" | jq -r '[.[].fields.assignee.displayName // "Unassigned"] | unique | .[]')
generate_dashboard() {
cat <<EOF
## š Review Progress Dashboard
**Last Updated:** $(date -u +"%Y-%m-%d %H:%M UTC")
**PR:** $pr_url
---
### Overall Progress
**Completion:** $completed_tasks of $total_tasks chunks ($completion_pct%)
\`\`\`
$(generate_progress_bar $completion_pct)
\`\`\`
| Status | Count | % |
|--------|-------|---|
| ā
Reviewed | $completed_tasks | $((completed_tasks * 100 / total_tasks))% |
| š In Progress | $in_progress_tasks | $((in_progress_tasks * 100 / total_tasks))% |
| ā³ Pending | $pending_tasks | $((pending_tasks * 100 / total_tasks))% |
### Time Metrics
| Metric | Value |
|--------|-------|
| Total Estimated | ~$total_estimated_min min |
| Remaining | ~$remaining_min min |
| Review Velocity | $(calculate_velocity) chunks/hour |
---
### Progress by Reviewer
$(generate_reviewer_table)
---
### Progress by Sub-Item
$(generate_subitem_table)
---
### Review Activity Timeline
$(generate_timeline)
---
### What's Next?
$(generate_next_actions)
---
š **Dashboard auto-updates** as reviews complete.
**ā Golden Armada** | *You ask - The Fleet Ships*
EOF
}
generate_progress_bar() {
pct=$1
filled=$((pct / 5)) # 20 chars total
empty=$((20 - filled))
bar=""
for i in $(seq 1 $filled); do bar+="ā"; done
for i in $(seq 1 $empty); do bar+="ā"; done
echo "[$bar] $pct%"
}
generate_reviewer_table() {
echo "| Reviewer | Chunks | Completed | Coverage | Status |"
echo "|----------|--------|-----------|----------|--------|"
for reviewer in $reviewers; do
assigned=$(echo "$review_tasks" | jq "[.[] | select(.fields.assignee.displayName == \"$reviewer\")] | length")
completed=$(echo "$review_tasks" | jq "[.[] | select(.fields.assignee.displayName == \"$reviewer\" and .fields.status.name == \"Done\")] | length")
# Determine coverage area from chunk summaries
coverage=$(echo "$review_tasks" | jq -r "[.[] | select(.fields.assignee.displayName == \"$reviewer\") | .fields.summary] | first | split(\" \")[2:4] | join(\" \")")
# Determine status
if [ $completed -eq $assigned ]; then
status="ā
Complete"
elif [ $completed -gt 0 ]; then
status="š Reviewing"
else
status="ā³ Not Started"
fi
echo "| @$reviewer | $assigned | $completed | $coverage | $status |"
done
# Add unassigned if any
unassigned=$(echo "$review_tasks" | jq '[.[] | select(.fields.assignee == null)] | length')
if [ $unassigned -gt 0 ]; then
echo "| ā Unassigned | $unassigned | 0 | - | ā ļø Needs Reviewer |"
fi
}
generate_subitem_table() {
echo "| # | Sub-Item | Focus | Reviewer | Est. | Status |"
echo "|---|----------|-------|----------|------|--------|"
idx=1
for task in $(echo "$review_tasks" | jq -c '.[]'); do
key=$(echo "$task" | jq -r '.key')
summary=$(echo "$task" | jq -r '.fields.summary' | cut -c1-30)
assignee=$(echo "$task" | jq -r '.fields.assignee.displayName // "Unassigned"')
estimate=$(echo "$task" | jq -r '.fields.timeestimate // 0')
estimate_min=$((estimate / 60))
status_name=$(echo "$task" | jq -r '.fields.status.name')
# Map status to icon
case "$status_name" in
"Done") status_icon="ā
" ;;
"In Progress") status_icon="š" ;;
*) status_icon="ā³" ;;
esac
echo "| $idx | [$key]($JIRA_BASE_URL/browse/$key) | $summary | @$assignee | ${estimate_min}m | $status_icon |"
((idx++))
done
}
generate_timeline() {
echo "Recent review activity:"
echo ""
# Get recent updates from review tasks
for task in $(echo "$review_tasks" | jq -c '.[]' | head -5); do
key=$(echo "$task" | jq -r '.key')
updated=$(echo "$task" | jq -r '.fields.updated')
status=$(echo "$task" | jq -r '.fields.status.name')
assignee=$(echo "$task" | jq -r '.fields.assignee.displayName // "Unassigned"')
# Format timestamp
time_ago=$(calculate_time_ago "$updated")
case "$status" in
"Done")
echo "- ā
**$key** reviewed by @$assignee ($time_ago)"
;;
"In Progress")
echo "- š **$key** being reviewed by @$assignee ($time_ago)"
;;
esac
done
}
generate_next_actions() {
# Find next priority chunks
pending=$(echo "$review_tasks" | jq -c '[.[] | select(.fields.status.name != "Done")] | sort_by(.fields.created) | .[0:3]')
echo "**Suggested next steps:**"
echo ""
# Unassigned chunks needing reviewers
unassigned=$(echo "$review_tasks" | jq '[.[] | select(.fields.assignee == null)] | length')
if [ $unassigned -gt 0 ]; then
echo "1. ā ļø **Assign reviewers** to $unassigned unassigned chunks"
fi
# Suggest next chunks for active reviewers
for reviewer in $reviewers; do
in_progress=$(echo "$review_tasks" | jq "[.[] | select(.fields.assignee.displayName == \"$reviewer\" and .fields.status.name == \"In Progress\")] | length")
remaining=$(echo "$review_tasks" | jq "[.[] | select(.fields.assignee.displayName == \"$reviewer\" and .fields.status.name != \"Done\")] | length")
if [ $in_progress -eq 0 ] && [ $remaining -gt 0 ]; then
next_chunk=$(echo "$review_tasks" | jq -r "[.[] | select(.fields.assignee.displayName == \"$reviewer\" and .fields.status.name != \"Done\")][0].key")
echo "1. @$reviewer: Pick up **$next_chunk** next"
fi
done
# Completion message if close
if [ $completion_pct -ge 80 ]; then
echo ""
echo "š **Almost there!** Just $pending_tasks chunks remaining."
fi
}
# Create initial dashboard
dashboard=$(generate_dashboard)
mcp__atlassian__addCommentToJiraIssue(
cloudId="$cloud_id",
issueIdOrKey="$parent_key",
commentBody="$dashboard"
)
# Store comment ID for updates
comment_id=$(get_last_comment_id "$parent_key")
save_dashboard_comment_id "$parent_key" "$comment_id"
Triggered when review activity is detected:
update_dashboard() {
parent_key=$1
comment_id=$(get_dashboard_comment_id "$parent_key")
# Regenerate dashboard with fresh data
dashboard=$(generate_dashboard)
# Note: Official Atlassian MCP doesn't have update_comment, so we add a new comment
mcp__atlassian__addCommentToJiraIssue(
cloudId="$cloud_id",
issueIdOrKey="$parent_key",
commentBody="$dashboard"
)
}
## š Review Progress Dashboard
**Last Updated:** 2025-12-19 15:30 UTC
**PR:** https://github.com/org/repo/pull/123
---
### Overall Progress
**Completion:** 8 of 12 chunks (67%)
[āāāāāāāāāāāāāāāāāāāā] 67%
| Status | Count | % |
|--------|-------|---|
| ā
Reviewed | 8 | 67% |
| š In Progress | 2 | 17% |
| ā³ Pending | 2 | 16% |
### Time Metrics
| Metric | Value |
|--------|-------|
| Total Estimated | ~45 min |
| Remaining | ~15 min |
| Review Velocity | 1.2 chunks/hour |
---
### Progress by Reviewer
| Reviewer | Chunks | Completed | Coverage | Status |
|----------|--------|-----------|----------|--------|
| @alice | 4 | 4 | Frontend | ā
Complete |
| @bob | 5 | 3 | Backend | š Reviewing |
| @charlie | 3 | 1 | Tests | š Reviewing |
---
### What's Next?
**Suggested next steps:**
1. @bob: Pick up **PROJ-206** next
2. @charlie: Pick up **PROJ-211** next
š **Almost there!** Just 4 chunks remaining.
---
š Dashboard auto-updates as reviews complete.
**ā Golden Armada** | *You ask - The Fleet Ships*
review-facilitator creates review tasksreview-facilitator: Creates the review chunks to trackreview-reminder-bot: Uses progress data for reminderscompletion-orchestrator: Reports overall progressā
Review Progress Dashboard Created
Parent Issue: PROJ-123
PR: https://github.com/org/repo/pull/456
Progress: 0 of 8 chunks (0%)
Reviewers: 3 assigned
Dashboard posted to PROJ-123.
Will auto-update as reviews complete.
Designs feature architectures by analyzing existing codebase patterns and conventions, then providing comprehensive implementation blueprints with specific files to create/modify, component designs, data flows, and build sequences