Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

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:

...