feat(grafana): jira sprint based dashboards#8574
feat(grafana): jira sprint based dashboards#8574Bhoopalan1999 wants to merge 8 commits intoapache:mainfrom
Conversation
Adds a new Grafana dashboard for Jira that is sprint-based rather than time-based. Some of the features: Hides the global time picker Introduces a sprint selection dropdown to scope all panels Does not modify the existing Kanban (time-based) dashboard
|
Hi @Bhoopalan1999 , I checked the dashboard and it's overall good.
I checked the SQL and found you joined tables like
|
Startrekzky
left a comment
There was a problem hiding this comment.
I left my comments under the PR
|
Hello @Startrekzky Thanks for the feedback. 1. Difference between Cycle Lead Time & Issue Lead Time: 2. The number of overall issue delivery rate is not consistent with the rate by sprint 3. Please remove all status/type/... filters only applicable to your own use cases. |
Fixed: 1. My biggest question is why there is a cycle time when Issue lead time already exists? They're the same to me. - Removed them 2. The number of overall issue delivery rate is not consistent with the rate by sprint - The possible reason is that issue_type was a custom variable in my dashboard and it is a query variable in existing Jira dashboard. Fixed it. 3. Please remove all status/type/... filters only applicable to your own use cases - Removed that in all tiles of the jira sprint dashboard
|
I've made the changes in the new commit:
|
|
Hello @Startrekzky Thanks for the feedback. I've updated all the changes requested. Also, I've now moved the file. Previously, I've accidentally kept the file inside grafana folder directly instead of grafana/dashboards. That's fixed now. Please review. |
|
@Startrekzky Can you find time to review the PR? Thanks. |
|
Please update the ASF header before we can merge—thanks! |
Startrekzky
left a comment
There was a problem hiding this comment.
Why are the files under /backend/plugins updated?
|
Hi, Just recently came across this thread and wanted to share how I have been reporting Sprints in my instance. A key difference in my approach is that I use Full query below, if of any help. WITH sprint_data AS (
-- Get sprint info and explicitly filter to the current Board loop
SELECT DISTINCT
s.id AS sprint_id,
s.name AS sprint_name,
s.started_date,
s.completed_date
FROM sprints s
JOIN boards b ON s.original_board_id = b.id
WHERE
s.name REGEXP CONCAT('^', '${Sprints:regex}')
AND $__timeFilter(s.started_date)
-- This restricts the sprints to the board currently being rendered
AND (b.name IN ("${Boards}") OR "${Boards}" = '')
),
sprint_issues_base AS (
SELECT
j.id AS issue_id,
j.issue_key,
j.status AS current_status,
j.story_point AS current_story_points,
j.original_type,
j.assignee_name,
j.original_project,
sd.sprint_id,
sd.sprint_name,
sd.started_date,
sd.completed_date
FROM issues j
JOIN sprint_issues spi ON spi.issue_id = j.id
JOIN sprint_data sd ON spi.sprint_id = sd.sprint_id
LEFT JOIN board_issues boi ON boi.issue_id = j.id
LEFT JOIN boards bo ON bo.id = boi.board_id
WHERE j.original_type NOT IN ('Epic', 'Sub-task')
AND (j.assignee_name IN ($Person) OR $Person = '')
AND (bo.name IN ("${Boards}") OR "${Boards}" = '')
AND j.original_project = "${JiraProjects}"
),
added_to_sprint AS (
SELECT
sib.issue_id,
sib.sprint_id,
sib.issue_key,
sib.current_status,
sib.current_story_points,
TIMESTAMP(sib.started_date) as time,
sib.sprint_name,
sib.started_date,
sib.completed_date,
-- Find the first changelog entry where this sprint was added to the issue
(SELECT MIN(icl.created_date)
FROM issue_changelogs icl
WHERE icl.issue_id = sib.issue_id
AND icl.field_name = 'Sprint'
AND icl.original_to_value LIKE CONCAT('%', sib.sprint_id, '%')
-- And the sprint was NOT in the "from" value (i.e., it was actually added, not just moved)
AND (icl.original_from_value NOT LIKE CONCAT('%', sib.sprint_id, '%') OR icl.original_from_value IS NULL)
) AS added_date,
NULL as removed_date
FROM sprint_issues_base sib
),
removed_from_sprint AS (
SELECT
j.id AS issue_id,
sd.sprint_id,
j.issue_key,
j.status AS current_status,
j.story_point AS current_story_points,
TIMESTAMP(sd.started_date) as time,
sd.sprint_name,
sd.started_date,
sd.completed_date,
NULL as added_date,
icl.created_date AS removed_date
FROM issues j
JOIN issue_changelogs icl ON icl.issue_id = j.id
JOIN sprint_data sd ON 1=1
LEFT JOIN board_issues boi ON boi.issue_id = j.id
LEFT JOIN boards bo ON bo.id = boi.board_id
WHERE
-- Sprint field change
icl.field_name = 'Sprint'
-- Was in this sprint (from value contains sprint ID)
AND (icl.original_from_value LIKE CONCAT('%', sd.sprint_id, '%') OR icl.original_to_value IS NULL)
-- Was removed from this sprint (to value does NOT contain sprint ID or is null)
AND (icl.original_to_value NOT LIKE CONCAT('%', sd.sprint_id, '%') OR icl.original_to_value IS NULL)
-- Removal happened during the sprint window
AND icl.created_date >= sd.started_date
AND (icl.created_date <= sd.completed_date OR sd.completed_date IS NULL)
-- Filters
AND j.original_type NOT IN ('Epic', 'Sub-task')
AND (bo.name IN ("${Boards}") OR "${Boards}" = '')
AND j.original_project = "${JiraProjects}"
-- Ensure issue is NOT currently in the sprint (wasn't re-added)
AND NOT EXISTS (
SELECT 1 FROM sprint_issues spi
WHERE spi.issue_id = j.id AND spi.sprint_id = sd.sprint_id
)
),
all_sprint_issues AS (
SELECT
asp.* FROM added_to_sprint asp
UNION ALL
SELECT
rsp.* FROM removed_from_sprint rsp
),
status_at_sprint_end AS (
SELECT
asi.*,
-- Get the most recent status BEFORE or AT the reference date
(SELECT icl.to_value
FROM issue_changelogs icl
WHERE icl.issue_id = asi.issue_id
AND icl.field_name = 'status'
AND icl.created_date <= asi.completed_date
ORDER BY icl.created_date DESC
LIMIT 1
) AS last_status_before_sprint,
-- Get the FIRST status change ever (to determine initial state)
(SELECT icl.from_value
FROM issue_changelogs icl
WHERE icl.issue_id = asi.issue_id
AND icl.field_name = 'status'
ORDER BY icl.created_date ASC
LIMIT 1
) AS initial_status
FROM all_sprint_issues asi
),
status_at_sprint_end_final AS (
SELECT
sase.*,
COALESCE(last_status_before_sprint, initial_status, "TODO") as status_in_sprint
FROM status_at_sprint_end sase
),
story_points_at_sprint_end AS (
SELECT
asi.*,
COALESCE(
-- If there was a change AFTER reference date, get the "from" value of the earliest change
(SELECT CAST(icl.original_to_value AS DECIMAL(10,1))
FROM issue_changelogs icl
WHERE icl.issue_id = asi.issue_id
AND icl.field_name = 'Story Points'
AND icl.created_date <= asi.completed_date
ORDER BY icl.created_date DESC
LIMIT 1),
(SELECT
CASE
WHEN icl.original_from_value IS NULL OR TRIM(icl.original_from_value) = ''
THEN 0 -- Story points were NULL at sprint end (ticket had no points initially)
ELSE CAST(icl.original_from_value AS DECIMAL(10,1)) -- Use the from_value as initial
END
FROM issue_changelogs icl
WHERE icl.issue_id = asi.issue_id
AND icl.field_name = 'Story Points'
ORDER BY icl.created_date ASC
LIMIT 1),
asi.current_story_points
) AS historical_story_points
FROM status_at_sprint_end_final asi
)
SELECT * FROM story_points_at_sprint_end ORDER BY started_date ASC |



Adds a new Grafana dashboard for Jira that is sprint-based rather than time-based. Some of the features:
Hides the global time picker
Introduces a sprint selection dropdown to scope all panels Does not modify the existing Kanban (time-based) dashboard
pr-type/bug-fix,pr-type/feature-development, etc.Summary
What does this PR do?
The PR adds a new Grafana dashboard for Jira. While the existing Jira dashboard is used for time based Kanban boards, this PR contributes an additional Jira board which is used for sprint boards. The board doesn't have time picker. Instead, I have added sprint dropdown. All tiles correspond to the sprint dropdown.
Screenshots
Sprint dropdown with 'Multiple selection' and 'All' option. Time picker is removed
