Jira issue limits report guide

This report utilizes the Jira “get issue limit“ API, and is not yet added to the Report Builder gallery permanently. However, you can import it using the JSON code provided on this page.

Report description

This report provides the following data and capabilities at a glance:

  • Current limits for attachments, worklogs, issue links, remote issue links and comments

  • Number of issues approaching those limits

  • Number of issues breaching those limits

  • Direct access to the standard Jira issue navigator to list the affected issues for further analysis and management

 

image-20240716-143255.png
Report in a nutshell

Steps to add this to your list of Report Builder reports

Step 1

Download Report Builder from the Atlassian Marketplace

Step 2

Copy the JSON code below:

{ "version": "0dc4f303-627f-4dbb-8109-edca6d3ead9b", "category": "scriptedReport", "tags": [], "script": "SR.render({}, async () => {\r\n const cardContainer = document.getElementById('cardContainer');\r\n\r\n try {\r\n // Fetch input values\r\n const cardsPerRowField = 'cards-per-row';\r\n const cardsPerRow = await SR.getValueByFieldName(cardsPerRowField) || 3;\r\n const cardWidthPercentage = 100 / cardsPerRow;\r\n\r\n // Set CSS for card container dynamically\r\n const styleElement = document.createElement('style');\r\n styleElement.textContent = `\r\n .card {\r\n width: calc(${cardWidthPercentage}% - 16px);\r\n }\r\n `;\r\n document.head.appendChild(styleElement);\r\n\r\n // Fetch the base URL\r\n const baseUrl = await SR.jira.getHostBaseUrl();\r\n\r\n // Fetch the capacity limits data from the API\r\n const response = await SR.request('/rest/api/3/issue/limit/report');\r\n const data = await response.json(); // Ensuring the response is correctly parsed as JSON\r\n\r\n const limits = data.limits || {};\r\n const issuesApproachingLimit = data.issuesApproachingLimit || {};\r\n const issuesBreachingLimit = data.issuesBreachingLimit || {};\r\n\r\n cardContainer.innerHTML = '';\r\n\r\n function createJqlUrl(issueIds) {\r\n const jqlQuery = `id in (${issueIds.join(',')})`;\r\n return `${baseUrl}/issues/?jql=${encodeURIComponent(jqlQuery)}`;\r\n }\r\n\r\n function processIssuesData(issuesData) {\r\n const issueIds = [];\r\n for (const issueType in issuesData) {\r\n if (issuesData.hasOwnProperty(issueType)) {\r\n const issues = issuesData[issueType];\r\n if (issues) {\r\n issueIds.push(...Object.keys(issues));\r\n }\r\n }\r\n }\r\n return issueIds;\r\n }\r\n\r\n function getCardColor(hasApproachingIssues, hasBreachingIssues) {\r\n if (hasBreachingIssues) {\r\n return '#c90000'; // Red \r\n } else if (hasApproachingIssues) {\r\n return '#ffba00'; // Yellow \r\n } else {\r\n return '#05bf00'; // Green \r\n }\r\n }\r\n\r\n Object.keys(limits).forEach(limitType => {\r\n const limitValue = limits[limitType];\r\n const approachingIssueIds = processIssuesData(issuesApproachingLimit[limitType] || {});\r\n const hasApproachingIssues = approachingIssueIds.length > 0;\r\n const breachingIssueIds = processIssuesData(issuesBreachingLimit[limitType] || {});\r\n const hasBreachingIssues = breachingIssueIds.length > 0;\r\n\r\n const card = document.createElement('div');\r\n card.className = 'card';\r\n card.style.border = '1px solid' + getCardColor(hasApproachingIssues, hasBreachingIssues);\r\n card.style.color = '#253858';\r\n\r\n const titleElement = document.createElement('p');\r\n titleElement.classList.add('title');\r\n\r\n switch(limitType) {\r\n case \"worklog\":\r\n titleElement.textContent = \"Worklogs\";\r\n break;\r\n case \"attachment\":\r\n titleElement.textContent = \"Attachments\";\r\n break;\r\n case \"remoteIssueLinks\":\r\n titleElement.textContent = \"Remote Issue Links\";\r\n break;\r\n case \"issuelinks\":\r\n titleElement.textContent = \"Issue Links\";\r\n break;\r\n case \"comment\":\r\n titleElement.textContent = \"Comments\";\r\n break;\r\n default:\r\n titleElement.textContent = `For: ${limitType}`;\r\n }\r\n\r\n const limitElement = document.createElement('h3');\r\n limitElement.textContent = `${limitValue}`;\r\n\r\n const approachingCountElement = document.createElement('p');\r\n approachingCountElement.innerHTML = `Issues approaching limit: <a href=\"${createJqlUrl(approachingIssueIds)}\" target=\"_blank\" style=\"color: ` + getCardColor(hasApproachingIssues, hasBreachingIssues) + `\">${approachingIssueIds.length}</a>`;\r\n approachingCountElement.style.cursor = 'pointer';\r\n\r\n const breachingCountElement = document.createElement('p');\r\n breachingCountElement.innerHTML = `Issues breaching limit: <a href=\"${createJqlUrl(breachingIssueIds)}\" target=\"_blank\" style=\"color: ` + getCardColor(hasApproachingIssues, hasBreachingIssues) + `\">${breachingIssueIds.length}</a>`;\r\n breachingCountElement.style.cursor = 'pointer';\r\n\r\n card.appendChild(titleElement);\r\n card.appendChild(limitElement);\r\n card.appendChild(document.createElement(\"div\")).classList.add('divider'); \r\n card.appendChild(approachingCountElement);\r\n card.appendChild(breachingCountElement);\r\n\r\n cardContainer.appendChild(card);\r\n });\r\n } catch (error) {\r\n console.error('Error fetching limit data:', error);\r\n cardContainer.innerHTML = '<div>Error fetching limit data. Please try again later.</div>';\r\n }\r\n});\r\n", "template": "<div class=\"report-container\">\r\n <h2>Issue Content Limits</h2>\r\n <p>Shown are limits per issue. Click on the numbers to get to the issue navigator.</p>\r\n <div id=\"cardContainer\" class=\"card-container\">\r\n <!-- Cards will be injected here by the script -->\r\n </div>\r\n</div>\r\n\r\n<style>\r\n\r\n h2 {\r\n text-align: center;\r\n font-size: 40px;\r\n margin-bottom: -10px;\r\n font-weight: 300;\r\n }\r\n \r\n p {\r\n font-size: 20px;\r\n margin-bottom: 20px;\r\n text-align: center;\r\n font-weight: 300;\r\n color: #95a5a6;\r\n }\r\n\r\n .card-container {\r\n display: flex;\r\n flex-wrap: wrap;\r\n gap: 16px;\r\n justify-content: flex-start;\r\n }\r\n \r\n .card {\r\n border-radius: 12px;\r\n padding: 25px;\r\n box-sizing: border-box;\r\n text-align: center;\r\n margin-bottom: 16px;\r\n color: #fff;\r\n /*box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);*/\r\n transition: transform 0.2s ease-in-out;\r\n }\r\n .card:hover {\r\n /*transform: scale(1.05);*/\r\n transition: 0.2s ease-in-out;\r\n background-color: #f9f9f9 !important;\r\n }\r\n .card h3 {\r\n margin: 0;\r\n font-size: 70px;\r\n font-weight: 100;\r\n color: inherit; /* Inherit color from card */\r\n }\r\n .card p {\r\n margin: 10px 0 0;\r\n font-size: 16px;\r\n font-weight: normal;\r\n color: inherit; /* Inherit color from card */\r\n }\r\n \r\n .card p.title {\r\n width: max-content;\r\n padding: 5px 15px;\r\n margin: 0 auto 10px auto;\r\n color: white;\r\n background-color: #403c90;\r\n border-radius: 200px;\r\n }\r\n \r\n .card a {\r\n text-decoration: none;\r\n color: inherit; /* Inherit color from card */\r\n }\r\n .card a:hover {\r\n text-decoration: underline;\r\n }\r\n \r\n .card .divider {\r\n width: 90%;\r\n height: 1px;\r\n background-color: #cfc9d2;\r\n margin: 10px auto 15px auto;\r\n }\r\n \r\n</style>\r\n", "name": "Issues Content Limits 2", "fields": [ { "type": "2", "name": "cards-per-row", "title": "cards per row", "optionsList": [], "isMulti": false, "order": 5, "defaultValue": "5", "_id": "66c8335f3dd369710a728ee1" } ], "permissions": { "view": [ { "type": "private", "value": "private" } ], "edit": [ { "type": "private", "value": "private" } ] }, "filterBy": [] }

 

Step 3

Click “Import Scripted Report from JSON“ in Report Builder, and paste the code as shown in the following video:

 

Create report.mp4

After you have created the report you may share it with your colleagues, or add to a dashboard.

If you have any trouble, please raise a ticket in our support portal.