Skip to content

Instantly share code, notes, and snippets.

@dvdsmpsn
Last active April 25, 2025 12:48
Show Gist options
  • Select an option

  • Save dvdsmpsn/f660d548a1d89522fc6c to your computer and use it in GitHub Desktop.

Select an option

Save dvdsmpsn/f660d548a1d89522fc6c to your computer and use it in GitHub Desktop.
Confluence User Macro: Spaces By Category
## User Macro: spaces-by-category
##
## Created by: David Simpson <david@appfusions.com> 2014-08
## Adapted from Remo Siegwart's answer at http://web.archive.org/web/20140813094412/https://answers.atlassian.com/questions/274837/show-a-space-list-within-a-page-using-category-label
##
## @param Label:title=Space Category|type=string|required=true|desc=The category you want to list spaces from.
## try to get space category
#set ( $spaceLabel = $action.labelManager.getLabel( "team:${paramLabel}" ) )
## check if space category exists
#if ( $!spaceLabel )
## try to get spaces by category
#set ( $spaces = $action.labelManager.getSpacesWithLabel( $spaceLabel ) )
<ul class="spaces-by-category-user-macro">
#foreach ( $space in $spaces )
## check if current user can view space
#if ( $permissionHelper.canView( $action.remoteUser, $space ) )
<li><a href="$!space.urlPath">$!space.name</a></li>
#end
#end
</ul>
#set ( $d = "$") ## escape the dollar sign for jQuery in velocity
<script>
## Sort the list client side as this can't be done server side in a user macro.
AJS.toInit(function (${d}) {
${d}('.spaces-by-category-user-macro').each(function(){
var ${d}me = ${d}(this);
// Sort the list items
var listItems = ${d}me.children('li').get();
listItems.sort(function(x,y) {
var compareX = ${d}(x).text().toUpperCase();
var compareY = ${d}(y).text().toUpperCase();
return (compareX < compareY) ? -1 : (compareX > compareY) ? 1 : 0;
});
// Write the list items back to the DOM
${d}.each(listItems, function(index, item) { ${d}me.append(item); });
});
});
</script>
#else
<div class="aui-message warning">
<p class="title">
<span class="aui-icon icon-warning">Warning</span>
<strong>Space category not found</strong>
</p>
<p>Couldn't find space category <strong>$paramLabel</strong>!</p>
</div>
#end
@maltris
Copy link
Copy Markdown

maltris commented Oct 12, 2023

This stopped working somewhere between 8.1 and 8.6 of confluence. I added:

CATALINA_OPTS="-Dmacro.required.velocity.context.keys=permissionHelper,action ${CATALINA_OPTS}"

to my setenv.sh of confluence and it worked again.

@maltris
Copy link
Copy Markdown

maltris commented Apr 25, 2025

Confluence 9+ removed the action.labelManager and action.remoteUser methods and some more. By best friend the LLM and I rebuilt it into the REST API style:

## User Macro: spaces-by-category
##
## Created by: Malte Schmidt <m@maltris.org> as REST version
## Adapted from David Simpson <david@appfusions.com> 2014-08
## Adapted from Remo Siegwart's answer at http://web.archive.org/web/20140813094412/https://answers.atlassian.com/questions/274837/show-a-space-list-within-a-page-using-category-label
##
## @param Label:title=Space Label|type=string|required=true|desc=Label to search for (e.g. "product")

## Generate unique container ID based on macro instance
#set ($containerId = "spaces-by-label-" + $paramLabel)

<div id="$containerId" class="spaces-by-label">
  <p>Loading spaces with label "$paramLabel"...</p>
</div>

<script>
(function(containerId, label) {
  document.addEventListener('DOMContentLoaded', function() {
    var container = document.getElementById(containerId);
    if (!label.trim()) {
      container.innerHTML = '<div class="aui-message error">Please specify a label</div>';
      return;
    }

    fetch('/rest/api/space?label=' + encodeURIComponent(label))
      .then(function(response) {
        if (!response.ok) throw new Error('HTTP ' + response.status);
        return response.json();
      })
      .then(function(data) {
        if (data.results.length > 0) {
          var html = '<ul>';
          data.results.forEach(function(space) {
            html += '<li><a href="' + space._links.webui + '">' + space.name + '</a></li>';
          });
          container.innerHTML = html + '</ul>';
        } else {
          container.innerHTML = '<div class="aui-message info">No spaces with label "' + label + '"</div>';
        }
      })
      .catch(function(error) {
        container.innerHTML = '<div class="aui-message error">' + 
          (error.message.includes('403') ? 'Login required' : 'Error loading spaces') + 
          '</div>';
      });
  });
})("$containerId", "$paramLabel");
</script>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment