Categories
DailyOps

How to display scoped labels inside free version of GitLab

Display scoped labels inside free version of GitLab with the help of Greasemonkey a user script manager for Firefox web-browser.

I am using Gitlab free for personal development and operations. Scoped labels are essential to me as these little things help to identify things visually.

This solution does not implement any advanced functionality as it only updates the view for board, issues and labels.

Greasemonkey user script

I created the following Greasemonkey user script to identify and format scoped labels, assuming that this will stay a premium feature.

// ==UserScript==
// @name     GitLab scoped labels (view only)
// @version  7
// @grant    none
// @include  https://git.octocat.lab/* 
// ==/UserScript==


if(window.location.pathname.match(/.*\/boards/)) { // boards
  const callback = function(mutations, observer) {
    for(const mutation of mutations) {
      for(const addedElement of mutation.addedNodes) {
        const labels = document.querySelectorAll("span.gl-label");
        for(const label of labels) {
          if(label.innerText.includes("::")) {
            label.classList.add("gl-label-scoped")
            label.innerHTML = label.innerText.replace(/(\w*)::(\w*)/, "$1 $2");
          } else if(label.parentNode.classList.contains("board-title-text")) {
            console.log(label)
            label.classList.add("gl-label-scoped")
          }
        }
      }
    } 
  }
  const observer = new MutationObserver(callback)
  observer.observe(document, { childList: true, subtree: true })
} else if(window.location.pathname.match(/.*\/issues$/)) { // issues list
  const labels = document.querySelectorAll("span.gl-label");
  for(const label of labels) {
    if(label.firstChild.firstChild.innerText.includes("::")) {
      label.classList.add("gl-label-scoped")
      label.setAttribute("style", label.getAttribute("style") + label.firstChild.innerHTML.replace(/<.*style="background-color: (#\w*)">.*/, "--label-background-color: $1; --label-inset-border: inset 0 0 0 1px $1;"))
      label.firstChild.innerHTML = label.firstChild.innerHTML.replace(/<(.*)>(\w*)::(\w*)<\/span>/, "<$1>$2 $3")
    }
  }
} else if(window.location.pathname.match(/.*\/issues\/.*/)) { // issue details
  const menuLabels = document.querySelectorAll("span.gl-label");
  for(const label of menuLabels) {
    if(label.innerText.includes("::")) {      
      label.classList.add("gl-label-scoped")
      label.setAttribute("style", label.getAttribute("style") + label.firstChild.innerHTML.replace(/<.*style="background-color: (#\w*)">.*/, "--label-background-color: $1; --label-inset-border: inset 0 0 0 1px $1;"))
      label.firstChild.innerHTML = label.firstChild.innerHTML.replace(/(.*)(\w*)::(\w*)(.*)/, "$1 $2 $3$4")
    }
  }
  const callback = function(mutations, observer) {
    for(const mutation of mutations) {
      if(mutation.target.classList.contains("notes")) {
        for(const timeline of mutation.addedNodes) {      
          const labels = timeline.querySelectorAll("span.gl-label")
          for(const label of labels) {
            if(label.innerText.includes("::")) { 
              label.classList.add("gl-label-scoped")
              label.firstChild.innerHTML.replace(/<.* style="background-color: (#\w*)".*/, "--label-background-color: $1; --label-inset-border: inset 0 0 0 1px $1;")
              label.setAttribute("style", label.getAttribute("style") + label.firstChild.innerHTML.replace(/<.* style="background-color: (#\w*)".*/, "--label-background-color: $1; --label-inset-border: inset 0 0 0 1px $1;"))
              label.firstChild.innerHTML = label.firstChild.innerHTML.replace(/<(.*)>(\w*)::(\w*)<\/span>/, "<$1>$2 $3")
            }
          }
        }
      }
    }
  }    
  const observer = new MutationObserver(callback)
  observer.observe(document, { childList: true, subtree: true })
} else if(window.location.pathname.match(/.*\/labels/)) { // labels
  const labels = document.querySelectorAll("span.gl-label");
  for(const label of labels) {
    if(label.innerText.includes("::")) {      
      label.classList.add("gl-label-scoped")
      const color = label.innerHTML.replace(/<.*style="background-color: (#\w*)".*/, "$1")
      label.setAttribute("style", label.getAttribute("style") + "--label-background-color: " + color + "; --label-inset-border: inset 0 0 0 2px " + color + "; color " + color + ";")
      label.innerHTML = label.innerText.replace(/(\w*)::(\w*)/, "$1 $2");
    }
  }
}

Screenshots

Labels.

Edit label.

Issue board.

Issues.

Filtered issues.

Issue details.

GitHub greasemonkey-gitlab-scoped-labels repository.