...
Copy the JSON code below:
Code Block |
---|
{ "version": "0dc4f303-627f-4dbb-8109-edca6d3ead9b", "category": "scriptedReport", "tags": [], "script": "SR.render({}, async () => {\r\n // Define the container where we will inject the cards\r\n const cardContainer = document.getElementById('cardContainer');\r\n\r\n try {\r\n // DefineFetch input field namesvalues\r\n const cardsPerRowField = 'cards-per-row'; // Replace with actual field name\r\n\r\n //const FetchcardsPerRow input= values for ranges and layoutawait SR.getValueByFieldName(cardsPerRowField) || 3;\r\n const cardsPerRowcardWidthPercentage = SR.getValueByFieldName(cardsPerRowField) || 3; // Default to 3 if not set100 / cardsPerRow;\r\n\r\n // CalculateSet theCSS widthfor ofcard each card based on the number of cards per rowcontainer dynamically\r\n const styleElement = document.createElement('style');\r\n const cardWidthPercentagestyleElement.textContent = 100 / cardsPerRow;`\r\n\r\n // Set the CSS for the .card container dynamically{\r\n const styleElement = document.createElement('style');\r\n styleElement.textContent = `\r\n .card {\r\n width: calcwidth: 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 APSR.request('/rest/api/3/issue/limit/report');\r\n const data = JSONawait response.parsejson(response.body);\r\n\r\n // Extract the limits, issues approaching limit, and issues breaching limit // 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 // Clear any existing data in the card container\r\n cardContainer.innerHTML = '';\r\n\r\n // Function to create JQL URL for issue IDs\r\n function 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 to process issues data\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 to determine card color based on issue status\r\nfunction getCardColor(hasApproachingIssues, hasBreachingIssues) {\r\n functionif getCardColor(hasApproachingIssues, hasBreachingIssues) {\r\n if (hasBreachingIssues) {\r\n return '#c90000'; // Red \r\n // return 'linear-gradient(135deg, #e74c3c 0%, #c0392b 100%)'; // Red gradient } else if (hasApproachingIssues) {\r\n return '#c90000#ffba00'; // RedYellow \r\n } else if (hasApproachingIssues) {\r\n // return 'linear-gradient(135deg, #f39c12 0%, #e67e22 100%)#05bf00'; // YellowGreen gradient\r\n }\r\n return '#ffba00'; // Yellow }\r\n\r\n } else Object.keys(limits).forEach(limitType => {\r\n const limitValue = // return 'linear-gradient(135deg, #1abc9c 0%, #16a085 100%)'; // Green gradientlimits[limitType];\r\n const approachingIssueIds = processIssuesData(issuesApproachingLimit[limitType] || {});\r\n const hasApproachingIssues = approachingIssueIds.length return> '#05bf00'; // Green 0;\r\n const breachingIssueIds = processIssuesData(issuesBreachingLimit[limitType] || {});\r\n }\r\n\r\n const hasBreachingIssues = breachingIssueIds.length // Loop through each item in the limits node\r\n> 0;\r\n\r\n const card = Objectdocument.keyscreateElement(limits).forEach(limitType => {'div');\r\n const limitValuecard.className = limits[limitType]'card';\r\n\r\n // Get the list of issue IDs for issues approaching the limitcard.style.border = '1px solid' + getCardColor(hasApproachingIssues, hasBreachingIssues);\r\n const approachingIssueIds = processIssuesData(issuesApproachingLimit[limitType] || {})card.style.color = '#253858';\r\n\r\n const hasApproachingIssuestitleElement = approachingIssueIds.length > 0document.createElement('p');\r\n\r\n titleElement.classList.add('title');\r\n\r\n // Get the list of issue IDs for issues breaching the limitswitch(limitType) {\r\n const breachingIssueIds = processIssuesData(issuesBreachingLimit[limitType] || {}); case \"worklog\":\r\n const hasBreachingIssues = breachingIssueIdstitleElement.lengthtextContent >= 0;\r"Worklogs\n";\r\n // Create card element for each item in the limits nodebreak;\r\n const card = document.createElement('div');case \"attachment\":\r\n card.className titleElement.textContent = 'card'\"Attachments\";\r\n /* card.style.background = getCardColor(hasApproachingIssues, hasBreachingIssues); */ break;\r\n card.style.border = '1px solid' + getCardColor(hasApproachingIssues, hasBreachingIssues);case \"remoteIssueLinks\":\r\n card.style.color titleElement.textContent = '#253858';\r\n\"Remote Issue Links\";\r\n const titleElement = document.createElement('p') break;\r\n titleElement.classList.add('title'); case \"issuelinks\":\r\n // titleElement.textContent = `For: ${limitType}`;\r\n\"Issue Links\";\r\n break;\r\n if ( limitType == \"worklog\" ) { titleElement.textContent = case \"Worklogscomment\"; }:\r\n if ( limitType == \"attachment\" ) { titleElement.textContent = \"AttachmentsComments\"; }\r\n if ( limitType == \"remoteIssueLinks\" ) { titleElement.textContent = \"Remote Issue Links\"break; }\r\n if ( limitType == default:\"issuelinksr\"n ) { titleElement.textContent = \"Issue Links\"; }\r\n if (titleElement.textContent limitType= == \"comment\" ) { titleElement.textContent = \"Comments\";`For: ${limitType}`;\r\n }\r\n\r\n const limitElement = document.createElement('h3');\r\n // limitElement.textContent = `Limit: ${limitValue}`;\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 // Append elements to the card\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 // Append the card to the card container\r\n cardContainer.appendChild(card);\r\n });\r\n } catch (error) {\r\n console.error('Error fetching limit data:', error);\r\n // Optionally display an error message in the UI\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": "6684791b4aea9797226812d366c8335f3dd369710a728ee1" } ], "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:
...